webbrowser — u_pbt_webbrowser #
← Component reference · Guide contents
A web browser built into your window: page display, address bar, Back / Forward history, navigation context menu.
▶ See it live — Demo application, Web browser tile: the preview, the code behind it and this page, side by side.
At a glance #
| Userobject | u_pbt_webbrowser |
| Item class | — (component without items) |
| Used for | Displaying a web page, an internal portal, online documentation or generated HTML content without leaving the application |
Quick start #
// open event of the window
uo_browser.ib_address_bar = true // address bar + navigation buttons
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"
Setting is_address is the act of navigating: every assignment opens the requested page. An address without a protocol ("example.com") automatically receives https://. A disk path (C:\folder\page.html, \\server\share\page.html) becomes a file:/// address. Words that are not an address ("invoice 2026") go to the search engine of is_search_url; without one, they are refused and ue_error says so. A one-word server name followed by /, ? or # (office/, intranet/home) is an address, and so is an IPv6 address in brackets ([::1]/x); the word alone (intranet) stays free text. A server without HTTPS is written with an explicit http://.
Properties #
| Property | Type | Default | Purpose |
|---|---|---|---|
is_address | string | "" | Displayed address. Assigning this property triggers navigation. Reading it back gives the page actually displayed: if the user follows a link or goes back, it follows too (ue_load_completed tells you). Accepted schemes: http(s):, file: (a disk path too), about:, data:, mailto:, tel:; javascript: is refused |
ib_address_bar | boolean | false | Shows the built-in address bar: URL field, Back / Forward / Refresh buttons |
ib_context_menu | boolean | false | Turns on the right-click context menu: Back, Forward, Reload, plus Copy on a selection, Open link and Copy link address on a link, Copy image on an image. Opened from the keyboard (Shift+F10), it comes up on the element. In an input field, the Cut / Copy / Paste menu stays |
is_search_url | string | "" | Search engine for words that are not an address, %s = the encoded text (e.g. https://www.bing.com/search?q=%s). Empty by default: such a text is refused and ue_error is raised — a business application does not send what its users type to an engine it has not chosen. Only an http(s) address holding %s is accepted: any other raises ue_error and the engine in force stays |
ib_veto_new_window | boolean | false | Asks ue_new_window before opening a new window in the view; returning false keeps the current page |
ib_veto_downloads | boolean | false | Asks ue_download_starting before each download; returning false cancels it |
ib_veto_navigation | boolean | false | Asks ue_navigating before the site leaves for another page (a link, a form, a script); returning false keeps the current page. An allowed page is opened again at the address asked for: a form sent by POST loses its data |
ib_private | boolean | false | Private browsing: cookies, storage and cache of the sites are never written to the disk and vanish with the view. Set it before is_address: changing it reopens the view empty (no page, no history); setting it to true again opens a new private session |
is_title | string | "" | Title of the page on screen, read live (ue_title_changed tells you when it changes). Read-only: writing it changes nothing |
is_theme_style | string | "" | Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change |
is_theme_mode | string | "" | Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change |
il_theme_accent | long | -1 | Accent colour of this component (-1 = the application accent, or the theme's) |
Methods #
| Method | Purpose |
|---|---|
of_refresh ( ) | Reloads the current page. Returns 0 once asked, -4 if no page is shown (is_address empty), -2 if the component is not created |
of_go_back ( ) | Goes back to the previous page. Follows the order of your code: is_address then of_go_back() play in that order |
of_go_forward ( ) | Moves on to the next page |
of_can_go_back ( ) → boolean | true if a previous page exists — to enable or gray out your own Back button. Read live from the page; read it after a load (ue_load_completed) |
of_can_go_forward ( ) → boolean | true if a next page exists |
of_stop ( ) | Stops the current loading and drops the pages still waiting; the interrupted load raises ue_load_failed |
of_execute_javascript (string as_script) | Runs a script inside the displayed page and returns its value as JSON: a text comes back quoted, a number does not (42), a script that throws or returns nothing gives null. A long answer comes back whole. One condition, and it is structural: the page must be loaded, so call it from ue_load_completed, never right after setting is_address. Returns an empty string when there is no page yet or no answer within 5 seconds: of_get_last_error() says why |
of_show_html (string as_html) → long | Shows a page built by the application (an invoice, a letter). The page is encoded: a colour #c00, an anchor, a % or an accent is shown as written. At most 2 MB once encoded: beyond, ue_error and nothing changes. Returns 0 once sent, -2 if the component is not created |
of_clear_browsing_data ( ) → long | Clears what the sites stored: cookies (a signed-in session), local storage, cache, granted permissions. It takes its place after the addresses already set: the next page opens clean. Every webbrowser of the application shares this data. Returns 0 once sent, -2 if the component is not created |
of_reset ( ) | Resets the component: page cleared, navigation history erased, address bar hidden, context menu off, search engine emptied, questions (ib_veto_*) off, private browsing off. Cookies and sessions of the sites stay: that is of_clear_browsing_data. Returns 0 once applied, -2 if the component is not created |
of_save_as_png (string) · of_save_as_jpg (string) | Exports the displayed site as an image. Returns 0 once the image is written, -4 when writing fails, -2 when the component is not created |
Events #
| Event | Raised when |
|---|---|
ue_load_completed (string as_url) | A page has finished loading (yours, a link, Back, of_refresh); as_url is the address actually reached, redirections included. Not raised for an empty address (about:blank) nor for a failed load |
ue_load_failed (string as_url, long al_status) | A page could not be loaded: unknown host, no network, certificate, or a load cancelled by of_stop or by a newer address. al_status says why: see Why a page did not load |
ue_error (string as_message) | A text set in is_address (or typed in the bar) is not an address and no is_search_url is set, an address could not be opened at all, or the page's process stopped. Nothing else is held: the next address loads normally |
ue_new_window (string as_url) → boolean | The page asks for a new window after a click (target=_blank link, window.open): it opens in this view. Cancelable when ib_veto_new_window = true: returning false keeps the current page. A window opened by a script alone, with no click, is ignored. Only http and https addresses open: a site asking for a file, a data: page or a mail link gets ue_error. A file: link in a web page (http, https, data:) is refused by the engine itself, before the component: nothing opens and no event is raised |
ue_download_starting (string as_url, string as_path) → boolean | A download is starting: as_url is what is downloaded, as_path the file that will be written. Cancelable when ib_veto_downloads = true: returning false cancels it; otherwise it goes on as in Edge |
ue_navigating (string as_url) → boolean | The site is leaving for another page: a link, a form, a script — never an address set by your application. Cancelable when ib_veto_navigation = true: returning false keeps the current page |
ue_title_changed (string as_title) | The title of the page on screen changed (is_title reads it any time) |
ue_permission_requested (string as_url, string as_kind) → boolean | The site asks for the camera, the microphone, the position… (as_kind = a PERMISSION_* constant). Refused unless the event returns true: the one question of the library where silence means NO |
ue_ready ( ) | The component has finished loading; everything sent beforehand has been replayed |
ue_runtime_missing ( ) | The WebView2 runtime is missing: the component stays empty |
ue_bg_color (long al_color) | The component has computed its theme background color; the userobject has already adopted it (backcolor) |
ue_script_error (string as_message, string as_stack) | A JavaScript error happened in the component's address bar (never in the displayed site) |
Navigating #
The built-in address bar #
This is the fastest option: one property, and the user gets a URL field and Back / Forward / Refresh buttons, themed like the rest of the application.
// The address bar, then the page to open
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://fr.wikipedia.org/wiki/PowerBuilder"
The buttons gray themselves out when there is nowhere to go. In the address field, F5 (or Ctrl+R) reloads, Alt+← / Alt+→ go back and forward (swapped in right-to-left writing), Esc brings back the current address after an abandoned edit, and the first click selects the whole address.
Your own buttons #
If you would rather drive navigation from your own toolbar, hide the built-in bar and use the methods:
// Back / Forward buttons of your window
uo_browser.of_go_back()
uo_browser.of_go_forward()
// ue_load_completed event of uo_browser : (string as_url)
// Update the state of your buttons after each 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()
// And reflect the real address (redirections included)
sle_url.text = as_url
The navigation context menu #
ib_context_menu adds a small Back / Forward / Refresh menu on right-click, themed and rendered by the application. It follows what is under the mouse: Copy on selected text, Open link and Copy link address on a link, Copy image on an image. Opened from the keyboard (Shift+F10, Menu key), it comes up on the element. It shares exactly the same history as the address bar, so the two always stay consistent.
// A small menu on a right click : back, forward, refresh
uo_browser.ib_context_menu = true
Stopping a load #
// Stop button : interrupts a page that is taking too long
uo_browser.of_stop()
Words instead of an address #
By default, a text that is not an address is refused (ue_error), without holding anything: the next address loads normally. To turn it into a search, choose the engine:
// 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"
New windows and downloads #
An "open in a new tab" link or a sign-in window opened after a click is shown in the view, and ue_new_window tells you. A download goes on as in Edge, and ue_download_starting gives you the address and the file. Both turn into a question when you ask for it:
// 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"
Staying on your own servers #
ue_navigating is raised each time the site leaves for another page — a link, a form, a script —, never for an address set by your code. With ib_veto_navigation it is a question: returning false keeps the current page. An allowed page is opened again at the address the site asked for; a form sent by POST loses its data.
// 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
Camera, microphone, position #
When a site asks for the camera, the microphone, the position, notifications or reading the clipboard, ue_permission_requested decides, and the default answer is no: a site does not switch a camera on through a prompt the user does not understand. It is the one question of the library where silence means refusal. Nothing is remembered: the question comes back at each request.
// 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
Values of as_kind: PERMISSION_CAMERA, PERMISSION_MICROPHONE, PERMISSION_GEOLOCATION, PERMISSION_NOTIFICATIONS, PERMISSION_CLIPBOARD, PERMISSION_SENSORS, PERMISSION_DOWNLOADS (several downloads in a row), PERMISSION_FILES, PERMISSION_AUTOPLAY, PERMISSION_FONTS, PERMISSION_MIDI, PERMISSION_WINDOWS, PERMISSION_UNKNOWN.
Why a page did not load #
al_status of ue_load_failed is compared with the LOADSTATUS_* constants of the component:
| Constant | Means |
|---|---|
LOADSTATUS_HOST_NOT_RESOLVED | Unknown host (misspelt name, DNS) |
LOADSTATUS_DISCONNECTED · LOADSTATUS_CANNOT_CONNECT · LOADSTATUS_SERVER_UNREACHABLE | No network, server unreachable |
LOADSTATUS_TIMEOUT | The server did not answer in time |
LOADSTATUS_CERT_INVALID · LOADSTATUS_CERT_EXPIRED · LOADSTATUS_CERT_NAME_INCORRECT · LOADSTATUS_CERT_REVOKED · LOADSTATUS_CLIENT_CERT_ERROR | Certificate refused |
LOADSTATUS_CANCELED | Load cancelled by of_stop or by a newer address |
LOADSTATUS_AUTH_REQUIRED · LOADSTATUS_PROXY_AUTH_REQUIRED | Credentials required (server, proxy) |
LOADSTATUS_CONNECTION_ABORTED · LOADSTATUS_CONNECTION_RESET · LOADSTATUS_INVALID_RESPONSE · LOADSTATUS_REDIRECT_FAILED · LOADSTATUS_UNEXPECTED_ERROR · LOADSTATUS_UNKNOWN | Other connection or response failures |
// 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
Running a script in the page #
of_execute_javascript reads or changes the displayed page (its title, a field, a counter). It is not restricted by the licence, including on an about:blank or data: page: running a script in the page is what a browser is for, and the component is free.
// 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 that refuse embedded display #
Some sites — Google, most banks, many SaaS applications — send security headers that forbid being displayed inside another page. The component is not affected: it never shows a site in a frame. The page is opened as a top-level document, exactly as your own browser does, and those headers no longer apply.
So there is nothing to set, and no special case to handle in your code.
// A site that refuses to be embedded in a page : nothing special to do
uo_browser.ib_address_bar = true
uo_browser.is_address = "https://www.google.com"
In exchange, the page fills the whole component below the address bar: anything you would draw over it (banners, themed overlays) is not visible while browsing.
HTML content with no network #
of_show_html shows an HTML page built by your application: previewing a letter, a ticket, an invoice or a report, with no network call and no temporary file. The page is encoded for you: a colour #c00, an anchor, a % or an accent is shown as written (2 MB at most).
// 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)
Set straight into is_address, a data:text/html, address is not encoded: a # cuts the page there (everything after it is taken as an anchor) and a % garbles it. Prefer of_show_html, or encode it yourself (# → %23, % → %25).
A local file opens the same way with file:///C:/temp/report.html, or simply its path C:\temp\report.html.
Starting over #
of_reset() does more than clear the page: it erases the navigation history too. A user therefore cannot use the Back button to return to a page viewed by the previous user or in another file. It does not touch what the sites stored: cookies, signed-in sessions, local storage, permissions. On a shared workstation, the next user would arrive signed in as the previous one — of_clear_browsing_data() is what clears it. The sites live in a browsing profile of their own, separate from the components of the application.
// Switching to another file : start again from a clean browser, with no history
uo_browser.of_reset()
// Then the file, with its address bar
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()
For nothing to ever be written to the disk, set ib_private = true before the first address: cookies and storage vanish with the view.
This is the reflex to have whenever a single component is used to display content from different contexts.
Complete example #
// open event of the window : home page of the internal portal
uo_browser.of_reset() // start clean (history included)
// The navigation tools, then the home page
uo_browser.ib_address_bar = true // URL field + Back / Forward / Refresh
uo_browser.ib_context_menu = true // same navigation on right-click
uo_browser.is_address = "https://intranet.example.com/home"
// ue_load_completed event of uo_browser : (string as_url)
uo_status.of_panel(/*key*/ "main").is_text = "Page loaded: " + as_url
Best practices #
- Assign
is_address, do not call a navigation method: it is the property that triggers the page opening. - Turn
ib_address_baron as soon as the user is free to browse; keep driving with your own buttons for constrained workflows. - Rely on
of_can_go_back()/of_can_go_forward()for the state of your buttons rather than counting pages yourself: redirections would throw your count off. - Nothing to plan for sites that refuse embedded display: the page is always opened as a top-level document, so those headers do not apply.
- Call
of_reset()when switching context: it is the only way to guarantee that no previous page is reachable through the Back button. When the user of the workstation changes, addof_clear_browsing_data(): without it, cookies and sessions of the sites stay. - The component needs the web runtime installed on the machine: handle
ue_runtime_missingas you would for any other component (Installation). - A site may play sound without a user gesture: autoplay with sound is allowed in the whole WebView2 environment of the application (the video and sound players need it, a hidden page has no gesture). A page that starts a video with sound on opening will play it; if that is a problem, open addresses you know.
Inherited from the common base #
These members exist on every visual component — they are not specific to this one. They are detailed once, in the transverse chapters; this table only says where to read them.
| Members | Role | Detailed in |
|---|---|---|
of_reset | Put the component back to zero | 3.6 Resetting a component: of_reset() |
of_register_shortcut · of_clear_shortcuts | The component's keyboard chords | 3.5 Keyboard shortcuts |
of_is_created · of_is_ready · of_get_last_error | Whether it was born, whether it is ready, what failed | 3.7 Diagnostics |
of_save_as_png · of_save_as_jpg | Export the rendering as an image | 3.8 Exporting the rendering as an image |
of_set_redraw | Group changes into a single repaint | 3.10 Best practices |
of_preload_icons | Icons shown with no delay | Instant display: of_icon |
of_set_translation | Translate one of the component's labels | 5.2 Adapting a label: of_set_translation |
of_focus_webview | Give the component the focus | 6.4 Keyboard and focus |
of_print · of_print_to_pdf | Print, or write a PDF | 6.9 Printing |
of_set_property · of_get_property · of_component_name | Driving a property by its name | 3.1 The property engine |
Two helpers are not inherited: of_icon and of_escape_markup live on n_pbt_utils. Declare one — n_pbt_utils lnv_utils, nothing to create — and call them on it.