6. Cross-cutting features #
← Language and RTL · Contents · FAQ →
This chapter covers the services available whatever the component: tooltips, hosting PowerBuilder controls, drag and drop from Windows Explorer, keyboard focus, image export, and the non-visual utility objects.
6.1 Simple and rich tooltips #
Component tooltip #
uo_bouton.is_tooltip = "Save the file (Ctrl+S)"
The text accepts rich text markup: [b], [br], [color=…], [picture=…]…
Rich tooltip (title + text + image) #
For Office ribbon style contextual help:
uo_bouton.is_super_tooltip_title = "Save"
uo_bouton.is_super_tooltip_text = "Writes your changes to the server." &
+ "[br][br][size-=15]Shortcut: Ctrl+S[/size-=15]"
uo_bouton.is_super_tooltip_image = "img\help_save.png"
The three properties are independent: a title alone, or a title plus text with no image, are both valid. As soon as one is_super_tooltip_* property is set, it takes precedence over is_tooltip.
Item tooltip #
Every item class (n_pbt_item and its descendants) carries the same four properties:
uo_toolbar.of_bar("main").of_item("save").is_tooltip = "Save"
uo_tab.of_item("clients").is_super_tooltip_title = "Customers"
uo_tab.of_item("clients").is_super_tooltip_text = "128 records, last synced at 09:12"
Behavior #
- The tooltip is a themed native window, identical across all components (it is not confined by the boundaries of the webview).
- It does not appear when your application does not have the focus: hovering over a background window triggers nothing.
- It disappears when you switch to another application, and after 10 seconds at the latest.
of_reset()clears the tooltips set on the instance and on its items.
6.2 Hosting real PowerBuilder controls #
Container components do not display HTML in place of your screens: they host real PowerBuilder controls (userobjects, DataWindows, control groups), reparented as Win32 child windows. Your existing screens are reused as they are.
// Tabs: each page is a PB userobject
uo_tab.of_add_page("clients", "Customers", uo_page_clients)
uo_tab.of_add_page("factures", "Invoices", uo_page_factures, /*closable*/ true)
// Dockable panels: same principle
uo_dock.is_main = "doc" // center area
uo_dock.of_add_panel("doc", uo_dock.POSITION_STACK, "", 0, "Document", uo_editeur)
uo_dock.of_add_panel("explorer", uo_dock.POSITION_START, "", 240, "Explorer", uo_arbre)
uo_dock.of_add_panel("props", uo_dock.POSITION_END, "", 260, "Properties", uo_props)
What is handled for you:
- the positioning and resizing of the hosted control when the tab or panel changes size;
- showing / hiding it when the active tab or panel changes;
- floating, docked or auto-hidden panels (dockcontainer);
- clean destruction when the window closes.
⚠️ A hosted control is a native window: it is painted on top of the web layer. That is by design (your DataWindow stays crisp and fast), but it means no web effect — shadow, transparency, animation — can be drawn over it.
6.3 Receiving files from Windows Explorer #
A component can become a drop target for files dragged from Windows Explorer. The library installs a native drop target: you receive the full paths, which an HTML drop cannot give you.
uo_editeur.ib_allow_drop = true
// ue_drop_files event of uo_editeur: (string as_files[])
long ll_i
for ll_i = 1 to UpperBound(as_files)
of_ouvrir_fichier(as_files[ll_i])
next
| Event | Raised when |
|---|---|
ue_drag_enter ( ) | A file drag enters the component |
ue_drag_leave ( ) | It leaves without dropping |
ue_drop_files (string as_files[]) | The files are dropped — full paths |
The component provides the hover visual feedback itself (the drop zone is highlighted). Published by the components where dropping makes sense: statictext, codeeditor.
6.4 Keyboard and focus #
A PBToolboxAI component takes part in the keyboard navigation of your window just like a native control:
- the Tab key reaches it in the window tab order;
- keystrokes (arrows, Enter, Esc, typing) are handled by the component that has the focus;
- window shortcuts (Enter = default button, Esc = cancel) keep working even when the focus is inside a component.
To explicitly give the focus to a component's content (for example after opening a search panel):
uo_editeur.of_focus_webview()
6.5 Exporting the rendering as an image #
A reminder from the shared foundation: every component can be exported exactly as displayed.
uo_pivot.of_save_as_png("C:\temp\tableau.png")
uo_pivot.of_save_as_jpg("C:\temp\tableau.jpg")
Handy for attaching a chart to an email, feeding a report, or documenting a user incident.
6.6 Dialog boxes and notifications #
Two services that require no control on the window:
// Themed modal dialog box (synchronous return)
n_pbt_messagebox lnv_mb
lnv_mb = create n_pbt_messagebox
lnv_mb.is_title = "Delete"
lnv_mb.is_message = "Permanently delete [b]12 files[/b]?"
lnv_mb.is_icon = lnv_mb.ICON_QUESTION
lnv_mb.of_add_button("Delete", /*default*/ false, /*cancel*/ false)
lnv_mb.of_add_button("Cancel", /*default*/ true, /*cancel*/ true)
if lnv_mb.of_show(Handle(this)) = 1 then of_supprimer()
destroy lnv_mb
// Non-blocking "toast" notification in a screen corner
n_pbt_toaster lnv_toast
lnv_toast = create n_pbt_toaster
lnv_toast.is_title = "Import complete"
lnv_toast.is_text = "1,240 rows imported."
lnv_toast.is_kind = lnv_toast.KIND_SUCCESS
lnv_toast.of_show()
destroy lnv_toast
Full details: messagebox and toaster.
6.7 Non-visual utility objects #
Shipped in the same PBL, with no webview and no rendering: they are simple wrappers around the DLL. Create them, use them, destroy them.
Base64 encoding — u_pbt_base64 #
u_pbt_base64 lnv_b64
string ls_encode
lnv_b64 = create u_pbt_base64
ls_encode = lnv_b64.of_encode("Hello") // text -> UTF-8 -> Base64
ls_texte = lnv_b64.of_decode(ls_encode) // "" if the input is invalid
destroy lnv_b64
Hashes — u_pbt_hash #
u_pbt_hash lnv_hash
lnv_hash = create u_pbt_hash
ls_empreinte = lnv_hash.of_sha256("password") // lowercase hex
ls_fichier = lnv_hash.of_file("SHA256", "C:\livraison.zip")
destroy lnv_hash
| Method | Purpose |
|---|---|
of_string (string as_algo, string as_texte) | Hash of a string — MD5, SHA1, SHA256, SHA384, SHA512 |
of_file (string as_algo, string as_chemin) | Hash of a file's contents ("" if unreadable) |
of_md5 · of_sha1 · of_sha256 · of_sha512 | Shorthands |
Regular expressions — u_pbt_regex #
ECMAScript syntax, which PowerScript does not provide.
u_pbt_regex lnv_re
string ls_trouves[]
lnv_re = create u_pbt_regex
if lnv_re.of_is_match("^[\w.]+@[\w.]+\.\w{2,}$", ls_email) then …
ls_annee = lnv_re.of_match("(\d{4})-(\d{2})-(\d{2})", ls_date, /*group*/ 1)
ls_propre = lnv_re.of_replace("\s+", ls_saisie, " ")
ll_nb = lnv_re.of_match_all("[A-Z]{2}\d{6}", ls_texte, ls_trouves)
destroy lnv_re
| Method | Purpose |
|---|---|
of_is_match (pattern, text [, ab_ignore_case | al_flags]) | Does the text match? |
of_match (pattern, text, ai_groupe [, al_flags]) | First match (0 = whole match, 1.. = capturing group) |
of_match_all (pattern, text [, ai_groupe, al_flags], ref as_res[]) | All matches; returns the count |
of_replace (pattern, text, replacement) | Replaces every occurrence ($1… allowed) |
Options can be combined: FLAG_IGNORE_CASE (1), FLAG_SINGLELINE (2, . also matches line breaks).
Unique identifiers — u_pbt_guid #
u_pbt_guid lnv_guid
lnv_guid = create u_pbt_guid
ls_id = lnv_guid.of_new() // 1b4e28ba-2fa1-11d2-883f-0016d3cca427
ls_id = lnv_guid.of_new_braces() // {1b4e28ba-...}
ls_id = lnv_guid.of_new_plain() // 1b4e28ba2fa111d2883f0016d3cca427
destroy lnv_guid
ZIP archives — u_pbt_zip #
u_pbt_zip lnv_zip
lnv_zip = create u_pbt_zip
lnv_zip.of_compress("C:\temp\livraison.zip", "C:\appli\export") // file OR folder
lnv_zip.of_extract("C:\temp\livraison.zip", "C:\appli\import") // folder created if missing
destroy lnv_zip
Both methods return a boolean.
6.8 Library information #
// DLL version
string ls_version
ls_version = Space(32)
PBT_GetVersion(ls_version, 32)
| Global function | Purpose |
|---|---|
PBT_GetVersion (ref string, long) | Library version |
PBT_CheckRuntime (ref string, long) | Version of the installed WebView2 runtime (≤ 0 = missing) |
PBT_GetLastErrorMessage (ref string, long) | Last error message for the process |
PBT_LicenseStatus ( ) | License state — see License |
6.9 Printing #
Every component knows how to print itself, as displayed, with no intermediate DataWindow.
// Silent: a PDF on disk, nothing to click
uo_grille.of_print_to_pdf("C:\etats\ventes.pdf")
// Landscape, for a wide grid
uo_grille.of_print_to_pdf(/*fichier*/ "C:\etats\ventes.pdf", /*paysage*/ true)
// With a dialog: the user picks their printer and sees the preview
uo_grille.of_print()
// Straight to the system print dialog
uo_grille.of_print(/*dialogue systeme*/ true)
| Method | Purpose |
|---|---|
of_print_to_pdf (string as_path) · of_print_to_pdf (string, boolean ab_landscape) | Writes a PDF without showing anything. Returns only once the file is written (0 = done) |
of_print ( ) · of_print (boolean ab_system_dialog) | Opens the print dialog. Returns as soon as the dialog is up: what the user does with it is theirs |
⚠️ What is printed is what is RENDERED. A virtualized grid prints only the rows it holds: for a complete report, first switch to a layout that shows them all (pagination), or export the data rather than the rendering.
Return code -6 means the WebView2 runtime is too old to print (1.0.1108 for the PDF, 1.0.1587 for the dialog). Everything else follows the common return codes.