PBToolboxAI v4 ← 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

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, since it is the only one that makes [action=…] areas clickable (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. false forces a single 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 (0 = size from the theme)
il_text_colorlong-1Text color as RGB() (-1 = color from the theme). [color] tags still take precedence over their own span
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 (links and actions are inert when it is grayed out)
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

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
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
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 ( )Reads again the colour of the object the block sits on. With il_back_color and ii_corner_radius, the rounded corners show that colour, read when those two properties are set: call it after changing the BackColor of your window, or after moving the block to another parent. 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; read back, is_text holds every line, joined by [br]. With ib_follow_end the view stays at the bottom. 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)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
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[])
integer li

// 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

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.

// Once, when the window opens
uo_log.ib_follow_end = true
uo_log.is_text = "[b]Import[/b]"

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

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

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
of_is_created · of_is_ready · of_get_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 · of_component_nameDriving a property by its name3.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.


← Component reference · Guide contents