PBToolboxAI v5 ← Site

statictext — u_pbt_statictext #

← Component reference · Guide contents

Rich text block: markup, alignments, clickable links and actions, header look, scrolling mode (marquee) and file drop zone.

▶ See it live — Demo application, Statictext tile: the preview, the code behind it and this page, side by side.


At a glance #

Userobjectu_pbt_statictext
Item class— (component without items)
Used forReplacing a PowerBuilder statictext with a formatted, clickable text block that can act as a header, a scrolling banner or a drop zone
Opt-in optionsib_auto_height, ib_auto_width, ib_follow_end, ib_track_mouse, ib_track_cycle, ib_allow_drop, ib_selectable, ib_hover_effect, ib_ellipsis_tooltip, ib_marquee_overflow_only, ib_marquee_pause_on_hover, ib_mnemonic, ib_veto_links

Quick start #

// window open event
uo_text.is_text = "Welcome to [b][accent]PBToolboxAI[/accent][/b][br]" &
                   + "See the [hyperlink=https://pbtoolboxai.net]documentation[/hyperlink]."
uo_text.is_align = uo_text.ALIGN_CENTER
uo_text.is_valign = uo_text.VALIGN_CENTER

The text accepts rich text markup: this is the component that makes the most of it — its [action=…] areas raise ue_action and are reachable with the keyboard too (the message box makes them clickable as well; a [hyperlink=…] opens everywhere).


Constants #

ConstantValueFor
ALIGN_START · ALIGN_CENTER · ALIGN_END · ALIGN_JUSTIFY"start" "center" "end" "justify"is_align
VALIGN_TOP · VALIGN_CENTER · VALIGN_BOTTOM"top" "center" "bottom"is_valign

start and end are logical: they follow the writing direction (Language and RTL). The physical values left and right are still accepted as aliases.


Properties #

Text and formatting #

PropertyTypeDefaultPurpose
is_textstring""The text displayed, with rich text markup: [b], [i], [u], colors, [picture=…], [hyperlink=…], [action=…]
is_alignstring"start"Horizontal alignment: ALIGN_START, ALIGN_CENTER, ALIGN_END, ALIGN_JUSTIFY
is_valignstring"top"Vertical alignment within the control: VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM
ib_wrapbooleantrueAutomatic word wrap at the edge. false no longer folds long lines: they overflow, and only the line breaks of the text ([br], a new line) start a new line
ib_ellipsisbooleanfalseWith ib_wrap = false, truncates the overflow with an ellipsis instead of cutting it off
ib_ellipsis_tooltipbooleanfalseOpt-in: when the text does not fit the box, show it in full in a tooltip (markup included). Never replaces a tooltip you set yourself with is_tooltip or is_super_tooltip_*: yours wins
is_font_familystring""Default font for the block (empty = font from the theme)
ii_font_sizeinteger0Default size in points, from 6 to 200 like the [size] tag (0 = size from the theme, or the one PBT_SetDefaultFont gave). A value out of that range is brought back to the nearest bound, and read back as applied
il_text_colorlong-1Text color as RGB() (-1 = color from the theme). [color] tags still take precedence over their own span. A PowerBuilder SYSTEM colour (WindowText, ButtonFace…) means the colour of the theme, and reads back -1
ii_line_spacinginteger0Line spacing as a percentage, from 50 to 400 (150 = 1.5 lines; 0 = default). A value out of that range is brought back to the nearest bound, and read back as applied
ib_enabledbooleantrueBlock enabled or grayed out. Grayed out, links, actions and fold headers are inert and leave the Tab order; on the theme's surface the text takes the theme's grey, on a background of its own (il_back_color, a [bk] run) its colours are kept and attenuated: it stays readable
ib_selectablebooleanfalseOpt-in: lets the user select the text and copy it with Ctrl+C (off by default, like a label). Releasing the mouse after a selection does not raise ue_clicked
ii_max_linesinteger0At most N lines shown (0 = no limit): the last one ends with "…", the text counts as cut for ue_text_overflow and ib_ellipsis_tooltip, and ib_auto_height measures the lines shown. Not applied to a scrolling banner
ib_mnemonicbooleanfalseOpt-in: the & of the text marks the letter of a shortcut, as on a PowerBuilder StaticText — "&Name:" shows the N underlined, && writes one &. As in PowerBuilder, the shortcut itself belongs to the control the label names (its Accelerator). Off by default: "R&D" stays as written; is_text reads back with its &

Block look (the "header" look) #

PropertyTypeDefaultPurpose
il_back_colorlong-1Block background as RGB() (-1 = background from the theme). With ii_corner_radius it follows the rounded corners, and outside them the block shows the color of the object it sits on. It stays announced to PowerBuilder when the theme changes. A PowerBuilder SYSTEM colour (ButtonFace…) means the background of the theme, and reads back -1
il_border_colorlong-1Border color (-1 = no border)
ii_border_widthinteger0Border thickness in pixels (0 = no border)
ii_corner_radiusinteger0Corner rounding radius, in pixels. The border AND the il_back_color background follow it
ii_paddinginteger-1Inner margin in pixels: -1 = the theme's margin (default), 0 = no margin at all (the text lines up with the edge of a neighbouring field), more = pixels
ib_hover_effectbooleanfalseOpt-in: slight darkening on hover (lightening on a dark theme), for a label acting as a button

Scrolling mode (marquee) #

PropertyTypeDefaultPurpose
ib_marqueebooleanfalseTurns the block into a horizontally scrolling banner
ii_marquee_speedinteger60Scrolling speed, in pixels per second (0 = default speed, 60)
is_marquee_directionstringMARQUEE_STARTScrolling direction: MARQUEE_START (toward the start of the reading direction) or MARQUEE_END. The physical aliases "left" / "right" are accepted: they stay physical, whatever the reading direction. Any other value is taken, and read back, as MARQUEE_START
ib_marquee_overflow_onlybooleanfalseOpt-in: scroll only when the text is too wide for the box. A banner scrolling a text that already fits is pure visual noise. Off by default, so ib_marquee = true keeps meaning it scrolls
ib_marquee_pause_on_hoverbooleanfalseOpt-in: stop the scrolling while the pointer is over the block, so a long text can actually be read. The loop position is kept: nothing jumps when the pointer leaves

Optional interactions #

PropertyTypeDefaultPurpose
ib_allow_dropbooleanfalseOpt-in: accepts files dropped from Windows Explorer; the full paths arrive through ue_drop_files. A disabled text (ib_enabled = false) refuses every drop
ib_track_mousebooleanfalseOpt-in: enables ue_mouse_enter / ue_mouse_leave
ib_track_cyclebooleanfalseOpt-in: enables ue_cycle, raised at the end of each scrolling pass; without it, the text scrolls in silence
ib_auto_heightbooleanfalseOpt-in: the block measures its ideal height and resizes the userobject; see Shared foundation
ib_auto_widthbooleanfalseOpt-in: the userobject takes the WIDTH of its text — the longest line, without wrapping (the [br] breaks count), plus the padding and the border; a new text, a font or a padding resizes it again, and ue_auto_width tells the width settled on. A scrolling banner (ib_marquee) has no natural width and reports none
ib_follow_endbooleanfalseOpt-in, for a log written with of_append_text: the view stays at the BOTTOM as lines arrive — unless the reader scrolled up to read an older line: he is never pulled away from it
il_max_log_lineslong0For a log written with of_append_text: the number of lines kept (0 = all of them). Beyond it the oldest lines go, from the screen AND from is_text; the text set by is_text counts as one line. Lowering it cuts at once
ii_max_widthinteger0With ib_auto_width: the widest the userobject may grow, in pixels (0 = no limit). A longer text wraps at that width, and ib_auto_height takes over for the height
ib_veto_linksbooleanfalseOpt-in: before a [hyperlink] opens, ue_hyperlink_opening is asked; return FALSE to keep the link shut and handle it yourself (your own browser, a confirmation). Off by default, like every cancelable event of the library: the link opens at once
is_theme_stylestring""Visual style of the component (THEME_STYLE_* constants); empty = the application's, followed at every change
is_theme_modestring""Light or dark variant (THEME_MODE_* constants); empty = the application's, followed at every change
il_theme_accentlong-1Accent colour of this component (-1 = the application accent, or the theme's)
is_tooltipstring""Simple tooltip shown when hovering the component
is_super_tooltip_titlestring""Title of the rich tooltip (takes precedence over is_tooltip)
is_super_tooltip_textstring""Text of the rich tooltip (rich markup accepted)
is_super_tooltip_imagestring""Image of the rich tooltip

Methods #

MethodPurpose
of_reset ( )Resets every property to its default and clears the text. Returns 0 once applied, -2 when the component is not created
of_set_redraw (boolean)Groups a burst of changes into a single render. Returns 0 once applied, -2 when the component is not created
of_save_as_png (string) · of_save_as_jpg (string)Exports the rendering as an image. Returns 0 once the image is written, -4 when writing fails, -2 when the component is not created
of_refresh_parent_color ( )A block with a background (il_back_color) and rounded corners (ii_corner_radius) paints what lies OUTSIDE its corners with the colour of the object it sits on, so the corners look cut out. That colour is read when those two properties are set: if the window or the tab page behind the block changes its BackColor afterwards, the four corners keep the old colour — square patches around the block. Call this method then (or after moving the block to another parent) and the corners blend in again. Returns 0 once sent, -2 when the component is not created
of_scroll_to_end ( )Scrolls to the bottom of the text. For a log, whose newest line sits at the end: without it that line drops below the fold as soon as the text outgrows the visible height. Returns 0 once sent, -2 when the component is not created
of_append_text (string as_markup)Adds ONE line at the end of the text, for a log: only that line travels to the component and only that line is drawn — rewriting is_text at every line sent and drew the whole log again. as_markup takes the same markup as is_text; a line starts with no tag open, and an empty one keeps the height of a line. Read back, is_text holds every line, joined by [br], each one closing the tags it left open. With ib_follow_end the view stays at the bottom, with il_max_log_lines the oldest lines go; a screen reader announces each new line. Returns 0 once sent, -2 when the component is not created
of_clear ( )Empties the text, every line of a log included, and keeps every other setting (of_reset puts them all back to their defaults). Returns 0 once sent, -2 when the component is not created

Events #

EventRaised when
ue_clicked ( )Left click on the block — not raised on an [action] or [hyperlink] area (no duplicates), on the header of a [foldarea] (folding raises nothing), nor after a text selection
ue_hyperlink (string as_url, boolean ab_opened)A [hyperlink=url] zone was clicked. The browser opens on its own: the event reaches you as well, to log the click or do more with it. ab_opened says whether it really opened: FALSE for a scheme other than http, https or mailto (is_last_error says why), or when ue_hyperlink_opening kept it shut
ue_hyperlink_opening (string as_url) → booleanCancelable, asked before a [hyperlink=url] zone opens, only when ib_veto_links = true. Return FALSE to keep the link shut and handle it yourself: ue_hyperlink then arrives with ab_opened = FALSE. By default: TRUE
ue_action (string as_key)An [action=id] area has been clicked: it is up to you to hook your code in. The area is reachable with the keyboard too: Tab to it, then Enter or Space
ue_drop_files (string as_files[])Files have been dropped from Windows: full paths, one entry per file. Requires ib_allow_drop = true
ue_drag_enter ( )A file drag enters the component (ib_allow_drop)
ue_drag_leave ( )The file drag leaves the component
ue_auto_height (long al_height)The block has computed its ideal height — requires ib_auto_height = true
ue_auto_width (long al_width)The block has taken a new width, in PowerBuilder units — requires ib_auto_width = true
ue_rclicked ( )Right click on the block
ue_double_clicked ( )Double click on the block, like the native PowerBuilder StaticText. The single clicks that precede it are raised too, in the same order. Not raised on an [action] or [hyperlink] zone, which have their own channel
ue_text_overflow (boolean ab_truncated)The text stopped fitting the box — or fits again. Raised only on change, never as a flood: a wrapped block counts as cut when it is clipped at the bottom, a single-line one when it is cut on the side. Handle it to widen a column, offer a see more button, or simply switch ib_ellipsis_tooltip on
ue_mouse_enter ( )The mouse enters — requires ib_track_mouse = true
ue_mouse_leave ( )The mouse leaves — requires ib_track_mouse = true
ue_cycle ( )Scrolling mode only: the text has just finished a full pass (an animation INSIDE the text never counts as a pass) — requires ib_track_cycle = true
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)

Examples #

A section header #

Solid background, centered white text and a height fitted to the content: the block reads like a real title bar.

// Freeze the drawing while everything is set
uo_header.of_set_redraw(/*on*/ false)

// The title, centred
uo_header.is_text  = "[b]Sales dashboard"
uo_header.is_align = uo_header.ALIGN_CENTER

// Solid background and readable white text
uo_header.il_back_color = RGB(/*red*/ 60, /*green*/ 110, /*blue*/ 190)
uo_header.il_text_color = RGB(/*red*/ 255, /*green*/ 255, /*blue*/ 255)
uo_header.ii_padding = 14

// The block hugs its content : it reads like a title bar
uo_header.ib_auto_height = true

// Everything is drawn at once
uo_header.of_set_redraw(/*on*/ true)
// ue_auto_height event of uo_header
of_reposition_below_header(al_height)   // moves the content below the header
// A link to a web page, and an action your application handles (ue_action)
uo_text.is_text = "Your license expires on [b]12/31[/b]. " &
                   + "[hyperlink=https://pbtoolboxai.net]Learn more[/hyperlink] " &
                   + "or [action=renew]renew it now[/action]."
// ue_action event of uo_text : (string as_key)
choose case as_key
    case "renew" ; of_open_renewal()
end choose

ue_hyperlink is meant for URLs (the browser opens on its own); [action=id] is the right choice when the click has to stay inside your application. The [invisibleaction=id] variant raises the same ue_action without looking like a link.

A collapsible block #

// Two foldable sections : the second one starts folded
uo_recap.is_text = "[b]Order 2026-0148[/b][br]" &
                   + "[foldarea:[b]Delivery[/b]]Shipped on 12/07, within 48 hours.[/foldarea]" &
                   + "[foldarea-closed:[i]Legal notice[/i]]Returns accepted within 14 days.[/foldarea]"

// The block shrinks when a section is folded
uo_recap.ib_auto_height = true

A [foldarea:Title] adds a clickable header above its content: the reader folds the section with a click, and the marker turns from − into +. [foldarea-closed:Title] produces the same block, folded from the start. Blocks nest, and folding raises no event: it is a reading matter, not a coding one. When ib_auto_height is on, the height is reported again on every fold. The title is markup: [foldarea:[b][accent]Order 2026-0148[/accent][/b]] makes its own bold and accent-colored.

A scrolling banner #

// The message of the banner
uo_banner.is_text = "[b]Notice[/b] -- the service will be closed on Friday the 12th."

// Scrolling mode, news-ticker style
uo_banner.ib_marquee = true
uo_banner.ii_marquee_speed = 90        // pixels per second
uo_banner.is_marquee_direction = uo_banner.MARQUEE_START

The scrolling loops with no dead time. To stop it, set ib_marquee back to false: the text returns to its normal layout.

Once ib_track_cycle = true is set, the ue_cycle event is raised on every full pass of the text — handy for rotating several messages:

// In ue_cycle of the banner : move on to the next message
ii_message = Mod(ii_message, UpperBound(is_messages)) + 1
uo_banner.is_text = is_messages[ii_message]

A file drop zone #

// Accept files dragged from Windows Explorer
uo_zone.ib_allow_drop = true

// What the zone shows, centred
uo_zone.is_text = "[size=32][accent][b]Drop your files here[/b][/accent][/size][br][br]" &
                  + "Drag one or more files from Windows Explorer."
uo_zone.is_align  = uo_zone.ALIGN_CENTER
uo_zone.is_valign = uo_zone.VALIGN_CENTER
// ue_drop_files event of uo_zone : (string as_files[])
// Local variables
integer li

// The drop is over : the zone looks normal again
uo_zone.ii_border_width = 0

// Each dropped file, one after the other
for li = 1 to UpperBound(as_files)
    of_import(as_files[li])       // as_files[li] = FULL path of the file
next
// ue_drag_enter event of uo_zone : highlight the target while hovering
uo_zone.il_border_color = RGB(/*red*/ 21, /*green*/ 101, /*blue*/ 192)
uo_zone.ii_border_width = 2
// ue_drag_leave event of uo_zone : the drag went away, the zone looks normal again
uo_zone.ii_border_width = 0

The paths you receive are full paths: you can pass them straight to FileOpen or to your own import routine.

A label that behaves like a button #

// A text that behaves like a link button
uo_link.is_text = "Select all"
uo_link.il_text_color = RGB(/*red*/ 21, /*green*/ 101, /*blue*/ 192)
uo_link.ii_padding = 8
uo_link.ii_corner_radius = 6
uo_link.ib_hover_effect = true       // reacts to hover like a button
// ue_clicked event of uo_link
of_select_all()

A log written line by line #

Each call sends only the line added; ib_follow_end keeps the last one in view as long as the reader does not scroll up, and il_max_log_lines keeps only the newest ones.

// Local variables
long ll_row

// Once, when the window opens : the view follows the end, the 500 newest lines are kept
uo_log.ib_follow_end = true
uo_log.il_max_log_lines = 500
uo_log.is_text = "[b]Import[/b]"

// For every row imported : one line, sent alone
for ll_row = 1 to 2000
    uo_log.of_append_text(/*markup*/ "Row " + String(ll_row) + " [color=#2e7d32]imported[/color]")
next

A label as wide as its text #

// A status chip : background, rounded corners, and the width of its text
uo_status.is_text = "[b]Status :[/b] connected"
uo_status.il_back_color = RGB(/*red*/ 232, /*green*/ 245, /*blue*/ 233)
uo_status.ii_corner_radius = 12
uo_status.ib_auto_width = true

A field label written the PowerBuilder way #

A label taken over from a PowerBuilder StaticText keeps its &: with ib_mnemonic, the letter is underlined and && writes one &. As in PowerBuilder, the shortcut itself is the Accelerator of the field the label names.

// The & marks the shortcut letter : "Customer name:" with the C underlined
uo_label.ib_mnemonic = true
uo_label.is_text = "&Customer name:"

With ib_veto_links, ue_hyperlink_opening is asked before a [hyperlink] opens: returning FALSE keeps it shut — open it your own way, or ask for a confirmation — and ue_hyperlink then arrives with ab_opened = FALSE.

// Ask before a link opens
uo_text.ib_veto_links = true
uo_text.is_text = "See the [hyperlink=https://pbtoolboxai.net/doc/]documentation[/hyperlink]."
// ue_hyperlink_opening event of uo_text : (string as_url) returns boolean
// Only the pages of the company site open, every other link stays shut
return Left(as_url, 24) = "https://pbtoolboxai.net/"

Best practices #

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.

MembersRoleDetailed in
of_resetPut the component back to zero3.6 Resetting a component: of_reset()
of_register_shortcut · of_clear_shortcutsThe component's keyboard chords3.5 Keyboard shortcuts
ib_created · ib_ready · is_last_errorWhether it was born, whether it is ready, what failed3.7 Diagnostics
of_save_as_png · of_save_as_jpgExport the rendering as an image3.8 Exporting the rendering as an image
of_set_redrawGroup changes into a single repaint3.10 Best practices
of_preload_iconsIcons shown with no delayInstant display: of_icon
of_set_translationTranslate one of the component's labels5.2 Adapting a label: of_set_translation
of_focus_webviewGive the component the focus6.4 Keyboard and focus
of_print · of_print_to_pdfPrint, or write a PDF6.9 Printing
of_set_property · of_get_property · is_component_nameDriving a property by its name3.1 The property engine
is_accessible_name · is_accessible_descriptionThe name and description a screen reader says3.4 Optional properties and events

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.


← Component reference · Guide contents