PBToolboxAI v4 ← Site

webbrowser — u_pbt_webbrowser #

← Référence des composants · Sommaire du guide

Navigateur web intégré à votre fenêtre : affichage d'une page, barre d'adresse, historique Précédent / Suivant, menu contextuel de navigation.

▶ Le voir en vrai — Application de démonstration, tuile Web browser : l'aperçu, le code qui le produit et cette page, côte à côte.


En bref #

Userobjectu_pbt_webbrowser
Classe d'items— (composant sans items)
Sert àAfficher une page web, un portail interne, une documentation en ligne ou un contenu HTML généré, sans quitter l'application

Démarrage rapide #

// event open de la fenetre
uo_browser.ib_address_bar = true    // barre d'adresse + boutons de navigation
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"

Poser is_address est l'acte de navigation : chaque affectation ouvre la page demandée. Une adresse sans protocole ("exemple.com") reçoit automatiquement https://. Un chemin disque (C:\dossier\page.html, \\serveur\partage\page.html) devient une adresse file:///. Des mots qui ne sont pas une adresse ("facture 2026") partent vers le moteur de recherche de is_search_url ; sans moteur, ils sont refusés et ue_error le dit. Un nom de serveur d'un seul mot suivi de /, ? ou # (office/, intranet/home) est une adresse, comme une adresse IPv6 entre crochets ([::1]/x) ; le mot seul (intranet) reste un texte libre. Un serveur sans HTTPS s'écrit avec http:// explicite.


Propriétés #

PropriétéTypeDéfautRôle
is_addressstring""Adresse affichée. Affecter cette propriété déclenche la navigation. La relire donne la page réellement affichée : si l'utilisateur suit un lien ou revient en arrière, elle suit aussi (ue_load_completed vous prévient). Schémas acceptés : http(s):, file: (un chemin disque aussi), about:, data:, mailto:, tel: ; javascript: est refusé
ib_address_barbooleanfalseAffiche la barre d'adresse intégrée : champ URL, boutons Précédent / Suivant / Recharger
ib_context_menubooleanfalseActive le menu contextuel au clic droit : Précédent, Suivant, Recharger, plus Copier sur une sélection, Ouvrir le lien et Copier l'adresse du lien sur un lien, Copier l'image sur une image. Ouvert au clavier (Maj+F10), il se pose sur l'élément. Dans un champ de saisie, le menu Couper / Copier / Coller reste
is_search_urlstring""Moteur de recherche des mots qui ne sont pas une adresse, %s = le texte encodé (ex. https://www.bing.com/search?q=%s). Vide par défaut : un tel texte est refusé et ue_error est levé — une application métier n'envoie pas la frappe de ses utilisateurs à un moteur qu'elle n'a pas choisi. Seule une adresse http(s) contenant %s est acceptée : toute autre lève ue_error et le moteur en place reste
ib_veto_new_windowbooleanfalseDemande à ue_new_window avant d'ouvrir une nouvelle fenêtre dans la vue ; renvoyer false y laisse la page courante
ib_veto_downloadsbooleanfalseDemande à ue_download_starting avant chaque téléchargement ; renvoyer false l'annule
ib_veto_navigationbooleanfalseDemande à ue_navigating avant que le site parte vers une autre page (lien, formulaire, script) ; renvoyer false y laisse la page courante. Une page autorisée est rouverte à l'adresse demandée : un formulaire envoyé en POST y perd ses données
ib_privatebooleanfalseNavigation privée : cookies, stockage et cache des sites ne sont jamais écrits sur le disque et disparaissent avec la vue. À poser avant is_address : le changer rouvre la vue vide (ni page, ni historique) ; le reposer à true ouvre une session privée neuve
is_titlestring""Titre de la page affichée, lu en direct (ue_title_changed prévient quand il change). En lecture seule : l'écrire ne change rien
is_theme_stylestring""Style visuel du composant (constantes THEME_STYLE_*) ; vide = celui de l'application, suivi à chaque changement
is_theme_modestring""Variante claire ou sombre (constantes THEME_MODE_*) ; vide = celle de l'application, suivie à chaque changement
il_theme_accentlong-1Couleur d'accent de ce composant (-1 = l'accent de l'application, ou celui du thème)

Méthodes #

MéthodeRôle
of_refresh ( )Recharge la page courante. Renvoie 0 une fois demandé, -4 si aucune page n'est affichée (is_address vide), -2 si le composant n'est pas créé
of_go_back ( )Revient à la page précédente. Suit l'ordre de votre code : is_address puis of_go_back() jouent dans cet ordre
of_go_forward ( )Avance à la page suivante
of_can_go_back ( ) → booleantrue si une page précédente existe — pour activer ou griser votre bouton Précédent. Lu en direct sur la page ; à lire après un chargement (ue_load_completed)
of_can_go_forward ( ) → booleantrue si une page suivante existe
of_stop ( )Interrompt le chargement en cours et abandonne les pages encore en attente ; le chargement interrompu lève ue_load_failed
of_execute_javascript (string as_script)Exécute un script dans la page affichée et renvoie sa valeur en JSON : un texte revient entre guillemets, un nombre non (42), un script qui lève une erreur ou ne renvoie rien donne null. Une réponse longue revient entière. Une seule condition, et elle est structurelle : la page doit être chargée, donc appelez-la depuis ue_load_completed, jamais juste après avoir posé is_address. Renvoie une chaîne vide s'il n'y a pas encore de page ou sans réponse en 5 secondes : of_get_last_error() dit pourquoi
of_show_html (string as_html) → longAffiche une page construite par l'application (facture, courrier). La page est encodée : une couleur #c00, une ancre, un % ou un accent s'affichent tels qu'écrits. 2 Mo au plus une fois encodée : au-delà, ue_error et rien ne change. Renvoie 0 une fois envoyé, -2 si le composant n'est pas créé
of_clear_browsing_data ( ) → longEfface ce que les sites ont retenu : cookies (une session ouverte), stockage local, cache, permissions accordées. L'effacement prend sa place après les adresses déjà posées : la page suivante s'ouvre vierge. Tous les webbrowser de l'application partagent ces données. Renvoie 0 une fois envoyé, -2 si le composant n'est pas créé
of_reset ( )Remet le composant à neuf : page vidée, historique de navigation effacé, barre d'adresse masquée, menu contextuel désactivé, moteur de recherche vidé, demandes (ib_veto_*) désactivées, navigation privée coupée. Les cookies et sessions des sites restent : c'est of_clear_browsing_data. Renvoie 0 une fois appliqué, -2 si le composant n'est pas créé
of_save_as_png (string) · of_save_as_jpg (string)Exporte le site affiché en image. Renvoie 0 une fois l'image écrite, -4 si l'écriture échoue, -2 si le composant n'est pas créé

Événements #

ÉvénementDéclenché quand
ue_load_completed (string as_url)Une page a fini de se charger (la vôtre, un lien, Précédent, of_refresh) ; as_url est l'adresse effectivement atteinte, redirections comprises. Pas levé pour une adresse vide (about:blank) ni pour un chargement en échec
ue_load_failed (string as_url, long al_status)Une page n'a pas pu être chargée : hôte inconnu, pas de réseau, certificat, ou chargement annulé par of_stop ou par une adresse plus récente. al_status dit pourquoi : voir Pourquoi une page n'a pas chargé
ue_error (string as_message)Un texte posé dans is_address (ou tapé dans la barre) n'est pas une adresse et aucun is_search_url n'est posé, une adresse n'a pas pu être ouverte du tout, ou le processus de la page s'est arrêté. Rien d'autre n'est retenu : l'adresse suivante se charge normalement
ue_new_window (string as_url) → booleanLa page demande une nouvelle fenêtre après un clic (lien target=_blank, window.open) : elle s'ouvre dans cette vue. Annulable si ib_veto_new_window = true : renvoyer false garde la page courante. Une fenêtre ouverte par un script seul, sans clic, est ignorée. Seules les adresses http et https s'ouvrent : un site qui demande un fichier, une page data: ou un lien de courrier obtient ue_error. Un lien file: dans une page web (http, https, data:) est refusé par le moteur lui-même, avant le composant : rien ne s'ouvre et aucun événement n'est levé
ue_download_starting (string as_url, string as_path) → booleanUn téléchargement commence : as_url est ce qui est téléchargé, as_path le fichier qui sera écrit. Annulable si ib_veto_downloads = true : renvoyer false l'annule ; sinon il continue comme dans Edge
ue_navigating (string as_url) → booleanLe site part vers une autre page : un lien, un formulaire, un script — jamais une adresse posée par votre application. Annulable si ib_veto_navigation = true : renvoyer false garde la page courante
ue_title_changed (string as_title)Le titre de la page affichée a changé (is_title le relit à tout moment)
ue_permission_requested (string as_url, string as_kind) → booleanLe site demande la caméra, le micro, la position… (as_kind = une constante PERMISSION_*). Refusé sauf si l'événement renvoie true : la seule question de la bibliothèque où le silence vaut NON
ue_ready ( )Le composant a fini de charger ; tout ce qui a été envoyé avant a été rejoué
ue_runtime_missing ( )Le runtime WebView2 est absent : le composant reste vide
ue_bg_color (long al_color)Le composant a calculé sa couleur de fond de thème ; l'userobject l'a déjà adoptée (backcolor)
ue_script_error (string as_message, string as_stack)Une erreur JavaScript s'est produite dans la barre d'adresse du composant (jamais dans le site affiché)

La barre d'adresse intégrée #

C'est la solution la plus rapide : une propriété, et l'utilisateur dispose d'un champ URL et des boutons Précédent / Suivant / Recharger, thémés comme le reste de l'application.

// La barre d'adresse, puis la page a ouvrir
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"

Les boutons se grisent tout seuls quand il n'y a nulle part où aller. Dans le champ d'adresse, F5 (ou Ctrl+R) recharge, Alt+← / Alt+→ reviennent et avancent (inversés en écriture de droite à gauche), Échap rend l'adresse courante après une frappe abandonnée, et le premier clic sélectionne toute l'adresse.

Vos propres boutons #

Si vous préférez piloter la navigation depuis votre propre barre d'outils, masquez la barre intégrée et utilisez les méthodes :

// Boutons Precedent / Suivant de votre fenetre
uo_browser.of_go_back()
uo_browser.of_go_forward()
// event ue_load_completed de uo_browser : (string as_url)
// Mettre a jour l'etat de vos boutons apres chaque page
uo_toolbar.of_item(/*keys*/ "main/back").ib_enabled = uo_browser.of_can_go_back()
uo_toolbar.of_item(/*keys*/ "main/forward").ib_enabled   = uo_browser.of_can_go_forward()

// Et refleter l'adresse reelle (redirections comprises)
sle_url.text = as_url

Le menu contextuel de navigation #

ib_context_menu ajoute au clic droit un petit menu Précédent / Suivant / Recharger, thémé et rendu par l'application. Il suit ce qui est sous la souris : Copier sur un texte sélectionné, Ouvrir le lien et Copier l'adresse du lien sur un lien, Copier l'image sur une image. Ouvert au clavier (Maj+F10, touche Menu), il se pose sur l'élément. Il partage exactement le même historique que la barre d'adresse : les deux restent donc toujours cohérents.

// A small menu on a right click : back, forward, refresh
uo_browser.ib_context_menu = true

Arrêter un chargement #

// Bouton Stop : interrompt une page qui tarde
uo_browser.of_stop()

Des mots plutôt qu'une adresse #

Par défaut, un texte qui n'est pas une adresse est refusé (ue_error), sans rien bloquer : l'adresse suivante se charge normalement. Pour en faire une recherche, choisissez le moteur :

// Words typed in the address bar go to this engine (%s = the text)
uo_browser.is_search_url = "https://www.bing.com/search?q=%s"
uo_browser.is_address = "PowerBuilder WebView2"

Nouvelles fenêtres et téléchargements #

Un lien « ouvrir dans un nouvel onglet » ou une fenêtre de connexion ouverte après un clic s'affiche dans la vue, et ue_new_window vous le dit. Un téléchargement continue comme dans Edge, et ue_download_starting vous donne l'adresse et le fichier. Les deux se changent en question quand vous le demandez :

// Ask before each download
uo_browser.ib_veto_downloads = true
// ue_download_starting event of uo_browser : (string as_url, string as_path)
// Only PDF files may be downloaded
return Lower(Right(as_path, 4)) = ".pdf"

Rester sur ses serveurs #

ue_navigating est levé chaque fois que le site part vers une autre page — un lien, un formulaire, un script —, jamais pour une adresse posée par votre code. Avec ib_veto_navigation, c'est une question : renvoyer false y laisse la page courante. Une page autorisée est rouverte à l'adresse demandée par le site ; un formulaire envoyé en POST y perd ses données.

// Ask before the site leaves for another page
uo_browser.ib_veto_navigation = true
// ue_navigating event of uo_browser : (string as_url)
// Only the company servers may be opened
return Pos(Lower(as_url), "://intranet.example.com/") > 0

Caméra, micro, position #

Quand un site demande la caméra, le micro, la position, les notifications ou la lecture du presse-papiers, c'est ue_permission_requested qui décide, et la réponse par défaut est non : un site n'allume pas une caméra par une invite que l'utilisateur ne comprend pas. C'est la seule question de la bibliothèque où le silence vaut refus. Rien n'est retenu : la question revient à chaque demande.

// ue_permission_requested event of uo_browser : (string as_url, string as_kind)
// The video-call page of the company may use the camera and the microphone
if Pos(Lower(as_url), "://visio.example.com/") = 0 then return false
return as_kind = uo_browser.PERMISSION_CAMERA or as_kind = uo_browser.PERMISSION_MICROPHONE

Valeurs de as_kind : PERMISSION_CAMERA, PERMISSION_MICROPHONE, PERMISSION_GEOLOCATION, PERMISSION_NOTIFICATIONS, PERMISSION_CLIPBOARD, PERMISSION_SENSORS, PERMISSION_DOWNLOADS (plusieurs téléchargements d'affilée), PERMISSION_FILES, PERMISSION_AUTOPLAY, PERMISSION_FONTS, PERMISSION_MIDI, PERMISSION_WINDOWS, PERMISSION_UNKNOWN.

Pourquoi une page n'a pas chargé #

al_status de ue_load_failed se compare aux constantes LOADSTATUS_* du composant :

ConstanteSignifie
LOADSTATUS_HOST_NOT_RESOLVEDHôte inconnu (nom mal écrit, DNS)
LOADSTATUS_DISCONNECTED · LOADSTATUS_CANNOT_CONNECT · LOADSTATUS_SERVER_UNREACHABLEPas de réseau, serveur injoignable
LOADSTATUS_TIMEOUTLe serveur n'a pas répondu à temps
LOADSTATUS_CERT_INVALID · LOADSTATUS_CERT_EXPIRED · LOADSTATUS_CERT_NAME_INCORRECT · LOADSTATUS_CERT_REVOKED · LOADSTATUS_CLIENT_CERT_ERRORCertificat refusé
LOADSTATUS_CANCELEDChargement annulé par of_stop ou par une adresse plus récente
LOADSTATUS_AUTH_REQUIRED · LOADSTATUS_PROXY_AUTH_REQUIREDIdentification demandée (serveur, proxy)
LOADSTATUS_CONNECTION_ABORTED · LOADSTATUS_CONNECTION_RESET · LOADSTATUS_INVALID_RESPONSE · LOADSTATUS_REDIRECT_FAILED · LOADSTATUS_UNEXPECTED_ERROR · LOADSTATUS_UNKNOWNAutres échecs de connexion ou de réponse
// ue_load_failed event of uo_browser : (string as_url, long al_status)
if al_status = uo_browser.LOADSTATUS_HOST_NOT_RESOLVED then
	st_message.text = "Unknown address : " + as_url
end if

Exécuter un script dans la page #

of_execute_javascript lit ou modifie la page affichée (son titre, un champ, un compteur). Il n'est pas bridé par la licence, y compris sur une page about:blank ou data: : exécuter un script dans la page est le métier d'un navigateur, et le composant est gratuit.

// ue_load_completed event of uo_browser : (string as_url)
// The page title, as JSON : "PowerBuilder - Wikipedia" (quotes included)
sle_title.text = uo_browser.of_execute_javascript(/*script*/ "document.title")

Sites qui refusent l'affichage intégré #

Certains sites — Google, la plupart des banques, beaucoup d'applications SaaS — envoient des en-têtes de sécurité qui interdisent leur affichage à l'intérieur d'une autre page. Le composant n'est pas concerné : il n'affiche jamais un site dans un cadre. La page est ouverte comme document principal, exactement comme le fait votre navigateur, et ces en-têtes ne s'appliquent alors plus.

Il n'y a donc rien à régler, et aucun cas particulier à prévoir dans votre code.

// Un site qui refuse d'etre integre dans une page : rien de special a faire
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://www.google.com"

En contrepartie, la page occupe toute la surface du composant sous la barre d'adresse : les habillages posés par-dessus (bandeaux, superpositions thémées) ne sont pas visibles pendant la navigation.


Contenu HTML sans réseau #

of_show_html affiche une page HTML construite par votre application : un aperçu de courrier, un ticket, une facture ou un rapport, sans aucun appel réseau ni fichier temporaire. La page est encodée pour vous : une couleur #c00, une ancre, un % ou un accent s'affichent tels qu'écrits (2 Mo au plus).

// Local variables
string ls_html

// An order summary built by the application : the colour and the "%" come out as written
ls_html = "<html><body>" &
        + "<h1 style='color:#1f6feb'>Order #4152</h1>" &
        + "<p>Discount : 10%</p>" &
        + "</body></html>"
uo_browser.of_show_html(/*html*/ ls_html)

Posée directement dans is_address, une adresse data:text/html, n'est pas encodée : un # y coupe la page (tout ce qui suit passe pour une ancre) et un % la brouille. Préférez of_show_html, ou encodez vous-même (# → %23, % → %25).

Un fichier local s'ouvre de la même façon avec file:///C:/temp/rapport.html, ou simplement son chemin C:\temp\rapport.html.


Repartir de zéro #

of_reset() ne se contente pas de vider la page : il efface aussi l'historique de navigation. Un utilisateur ne peut donc pas revenir, par le bouton Précédent, sur une page consultée par l'utilisateur précédent ou dans un autre dossier. Il ne touche pas à ce que les sites ont retenu : cookies, sessions ouvertes, stockage local, permissions. Sur un poste partagé, l'utilisateur suivant arriverait connecté sous le compte du précédent — c'est of_clear_browsing_data() qui l'efface. Les sites vivent dans un profil de navigation à part, séparé des composants de l'application.

// Changement de dossier : on repart d'un navigateur vierge, sans historique
uo_browser.of_reset()

// Puis le dossier, avec sa barre d'adresse
uo_browser.ib_address_bar = true
uo_browser.is_address = ls_folder_url
// The user of the workstation changes : no page, no history, no signed-in session left
uo_browser.of_reset()
uo_browser.of_clear_browsing_data()

Pour que rien ne soit jamais écrit sur le disque, posez ib_private = true avant la première adresse : cookies et stockage disparaissent avec la vue.

C'est le réflexe à avoir chaque fois qu'un même composant sert à afficher des contenus de contextes différents.


Exemple complet #

// event open de la fenetre : page d'accueil du portail interne
uo_browser.of_reset()                  // repartir propre (historique compris)

// Les outils de navigation, puis la page d'accueil
uo_browser.ib_address_bar  = true      // champ URL + Precedent / Suivant / Recharger
uo_browser.ib_context_menu = true      // meme navigation au clic droit
uo_browser.is_address = "https://intranet.example.com/home"
// event ue_load_completed de uo_browser : (string as_url)
uo_status.of_panel(/*key*/ "main").is_text = "Page chargee : " + as_url

Bonnes pratiques #

Hérité du socle commun #

Ces membres existent sur tous les composants visuels — ils ne sont pas propres à celui-ci. Ils sont détaillés une seule fois, dans les chapitres transverses ; cette table dit seulement où les lire.

MembresRôleDétaillé dans
of_resetRemettre le composant à zéro3.6 Remettre un composant à zéro : of_reset()
of_register_shortcut · of_clear_shortcutsRaccourcis clavier du composant3.5 Les raccourcis clavier
of_is_created · of_is_ready · of_get_last_errorS'il est né, s'il est prêt, ce qui a échoué3.7 Diagnostic
of_save_as_png · of_save_as_jpgExporter le rendu en image3.8 Exporter le rendu en image
of_set_redrawGrouper les modifications en un seul repaint3.10 Bonnes pratiques
of_preload_iconsIcônes affichées sans délaiAffichage instantané : of_icon
of_set_translationTraduire un libellé du composant5.2 Adapter un libellé : of_set_translation
of_focus_webviewDonner le focus au composant6.4 Clavier et focus
of_print · of_print_to_pdfImprimer, ou écrire un PDF6.9 Imprimer
of_set_property · of_get_property · of_component_namePiloter une propriété par son nom3.1 Le moteur de propriétés

Deux aides ne sont pas héritées : of_icon et of_escape_markup vivent sur n_pbt_utils. Déclarez-en une — n_pbt_utils lnv_utils, rien à créer — et appelez-les dessus.


← Référence des composants · Sommaire du guide