PBToolboxAI v4 ← Site

picture — u_pbt_picture #

← Component reference · Guide contents

Image display: every common format, framing modes, alignment, automatic graying and a counter badge.

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


At a glance #

Userobjectu_pbt_picture
Item class— (component without items)
Used forReplacing a PowerBuilder picture: modern formats (SVG, WebP, animated GIF), controlled framing, clickable image, automatic graying
Opt-in optionsib_track_mouse

Quick start #

// window open event
uo_image.is_source  = "img\logo.png"
uo_image.is_stretch = uo_image.STRETCH_UNIFORM   // fits without distorting
uo_image.is_align   = uo_image.ALIGN_CENTER
uo_image.is_tooltip = "Company logo"

Where the image comes from: is_source #

is_source accepts four forms, all interchangeable:

FormExampleUse
Local fileimg\logo.pngpng, jpg, jfif, bmp, gif, ico, svg, webp, avif
Web addresshttps://…/logo.pngImage loaded from a server (https only: an http:// address is refused, see below)
Embedded datadata:image/png;base64,…Image already in memory, with no intermediate file
DLL resourceimg\packimages.dll:SAMPLEImage packaged in a resource DLL

An anim: prefix can be placed in front of a GIF to explicitly flag an animation (GIFs animate anyway).

When the same name exists under several resource types in a DLL, state the type: img\packimages.dll:PNG/SAMPLE, SVG/SAMPLE, ICON/APP, RCDATA/BLOB. See Images and icons for the mono: and tint: prefixes, which recolor a glyph according to the theme.

An http:// address is refused: the component's page is secure, and the engine would silently switch the image to https:// — on an intranet server without TLS it would then fail with a misleading message. The component therefore refuses it up front: error glyph and ue_error with REASON_INSECURE. For an image on an unencrypted server, download it first with n_pbt_restclient.of_download into a temporary folder, then show that path. Setting the same path again reads the file again: an image your application has just rewritten (photo, scan, crop) shows up, as with the native Picture. An image on disk is limited to 32 MB.


How it is framed: is_stretch #

ConstantEffect
STRETCH_UNIFORMDefault. The image is scaled without distortion and stays fully visible; margins may appear
STRETCH_UNIFORMTOFILLScaled without distortion, but the frame is filled completely; anything overflowing is cropped
STRETCH_FILLThe image is stretched to fit the frame exactly — it may be distorted
STRETCH_NONEOriginal size, no scaling

is_align decides the horizontal position of the image when it is smaller than the control: ALIGN_CENTER (default), ALIGN_START, ALIGN_END. The vertical axis has its own property, is_valign. The placement is read on screen: ALIGN_START stays on the leading edge whatever ii_rotation and ib_mirror. An unknown value reads back as center.


Constants #

ConstantValueFor
STRETCH_NONE · STRETCH_FILL · STRETCH_UNIFORM · STRETCH_UNIFORMTOFILL"none" "fill" "uniform" "uniformtofill"is_stretch
ALIGN_CENTER · ALIGN_START · ALIGN_END"center" "start" "end"is_align
VALIGN_TOP · VALIGN_CENTER · VALIGN_BOTTOM"top" "center" "bottom"is_valign
ROTATION_NONE · ROTATION_90 · ROTATION_180 · ROTATION_2700 90 180 270ii_rotation
REASON_NOT_FOUND · REASON_TOO_LARGE · REASON_INSECURE · REASON_UNSUPPORTED · REASON_FAILED"notfound" "toolarge" "insecure" "unsupported" "failed"ue_error (as_reason)

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


Properties #

PropertyTypeDefaultPurpose
is_sourcestring""The image to display (see the four forms above)
is_stretchstring"uniform"Framing mode: STRETCH_NONE, STRETCH_FILL, STRETCH_UNIFORM, STRETCH_UNIFORMTOFILL
is_alignstring"center"Horizontal placement when the image is smaller than the control: ALIGN_CENTER, ALIGN_START, ALIGN_END. The vertical axis is is_valign
is_valignstringVALIGN_CENTERVertical placement when the image is smaller than the control: VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM. The two axes are independent — is_align gives the column, this one the row — which is what makes a corner reachable
ib_enabledbooleantrueWhen false, the image is displayed in grayscale and answers nothing: clicks, wheel, keyboard and file drops
ii_badgeinteger0Counter badge in the top corner at the end of the line: right in a left-to-right reading, left in a right-to-left one (0 = none)
il_badge_colorlong-1Badge background, as a PowerBuilder RGB value (-1 = not set: the color that comes from the theme; 0 is black, like any other color). The text color is picked automatically so that the counter stays legible
ii_badge_sizeinteger0Badge height in pixels (0 = the size that comes from the theme). The font size follows on its own: the counter stays centered whatever the size
ib_track_mousebooleanfalseOpt-in: enables ue_mouse_enter / ue_mouse_leave
is_placeholderstring""Stand-in image, shown while is_source is empty (an « add a photo » frame, a silhouette). Displayed dimmed: a stand-in is not the content, and it is never announced as a loaded image. Accepts the mono: prefix, which recolours a monochrome glyph with the theme
is_error_sourcestring""Fallback image when the source fails to load. Leave it empty and the component shows its own error glyph — never an empty box, which tells the user nothing while ue_error only travels to your code. Accepts the mono: prefix
ii_rotationinteger0Quarter turns, for the scans and photos that arrive lying down: ROTATION_NONE, ROTATION_90, ROTATION_180, ROTATION_270 (anything else reads as 0). A quarter turn swaps the fitting axes as well, so the picture keeps its proportions instead of being squashed
ib_mirrorbooleanfalseHorizontal mirror on screen: the picture is flipped left to right, whatever ii_rotation
ib_zoomablebooleanfalseOpt-in: the user may come closer (wheel, towards the pointer, or the + and - keys), move around (drag, or the arrows — inverted in a right-to-left reading) and go back to the fitted view (double click, or 0); the 1 key shows the picture at its ACTUAL size, one pixel of the picture for one pixel of the screen. Larger than its frame, the picture always covers it: a drag never uncovers an empty band; smaller, it stays where is_align and is_valign put it. Only the left button drags it. For a plan, a scan or a photo — where four fixed fitting modes are not enough
id_zoomdouble1.0Zoom factor: 1.0 is the framing chosen by is_stretch, up to id_max_zoom (8.0 by default). Reading it back gives the current factor, wheel and keyboard included (ue_zoom_changed tells you each change: a gesture of the user, or this property set by your code). Needs ib_zoomable, set first: without it the factor stays 1.0
id_max_zoomdouble8.0The CEILING of the zoom, in the unit of id_zoom (1.0 = the fitted view): the wheel, the keys and id_zoom stop there. Any value from 1.0; under it, the default comes back. The ACTUAL size always stays reachable — the 1 key goes there, and a large scan shown small remains readable pixel for pixel. Lowered under the current zoom, the zoom comes down to it and ue_zoom_changed says so
ib_allow_dropbooleanfalseOpt-in: accepts files dropped from the Windows Explorer. The frame shows it is armed, and the full paths arrive through ue_drop_files — loading them into is_source is up to your application. A disabled picture (ib_enabled = false) refuses every drop, and ib_allow_drop still reads back as set
ib_auto_heightbooleanfalseOpt-in: the userobject takes the height that keeps the image's proportions at its current width. For a picture that height is deducible: no need to compute it yourself from the dimensions reported by ue_loaded
is_alt_textstring""Text alternative: what a screen reader says of the picture. Leave it empty for a purely decorative picture
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 removes the image. 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

Events #

EventRaised when
ue_clicked ( )Left click on the image. Dragging the zoomed picture is not a click, and a double click raises only one, like the native Picture
ue_loaded (long al_width, long al_height)The image has loaded; the arguments carry its original size in pixels
ue_error (string as_message, string as_reason)The image could not be loaded. as_message names the source (image load failed : <source>), as_reason says why: REASON_NOT_FOUND (missing file), REASON_TOO_LARGE (over 32 MB), REASON_INSECURE (an http:// address, refused), REASON_UNSUPPORTED (a format the component does not show), REASON_FAILED (anything else: a file that does not decode, a server that does not answer)
ue_rclicked ( )Right click on the image
ue_double_clicked ( )Double click on the image. One ue_clicked comes before it, never two — like the native Picture. When ib_zoomable is on, the double click also brings the picture back to the fitted view: the event is raised either way, and what it means is up to you
ue_zoom_changed (double ad_zoom)The zoom factor changed: wheel, double click, the +, - and 0 keys, or id_zoom set by your code — nothing when the factor stays the same. 1.0 means back to the framing of is_stretch
ue_auto_height (long al_height)The component settled on a new height; the userobject has already been resized when this fires. Needs ib_auto_height
ue_drop_files (string as_files[])Files dropped from the Explorer: full paths, one entry per file. Needs ib_allow_drop
ue_drag_enter ( )A file drag entered the component (ib_allow_drop)
ue_drag_leave ( )The file drag left the component
ue_mouse_enter ( )The mouse enters — requires ib_track_mouse = true
ue_mouse_leave ( )The mouse leaves — requires ib_track_mouse = 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 #

Showing the photo on a record #

// ue_row_changed event of the datawindow : show the photo of the current customer
uo_photo.is_source  = "photos\" + ls_customer_code + ".jpg"
uo_photo.is_stretch = uo_photo.STRETCH_UNIFORMTOFILL   // fills the frame, the overflow is cropped
uo_photo.is_align   = uo_photo.ALIGN_CENTER
// ue_error event of uo_photo : (string as_message, string as_reason)
if as_reason = uo_photo.REASON_NOT_FOUND then
    uo_photo.is_source = "img\photo_missing.svg"     // fallback image
end if

Handling ue_error is the right way to deal with a missing photo: there is no need to test whether the file exists before assigning it.

A clickable image, button-style #

// The picture, and the tooltip shown when the mouse rests on it
uo_avatar.is_source    = "photos\user.png"
uo_avatar.is_tooltip   = "My account"
// ue_clicked event of uo_avatar
of_open_my_account()

Counter and graying #

// A notification badge on a mail icon
uo_mail.is_source = "img\packimages.dll:SVG/MAIL"
uo_mail.ii_badge  = ll_unread       // 0 makes the badge disappear

// Red beyond a threshold, theme color otherwise (-1)
if ll_unread > 20 then
    uo_mail.il_badge_color = RGB(/*red*/ 200, /*green*/ 30, /*blue*/ 30)
else
    uo_mail.il_badge_color = -1
end if

// Feature unavailable : the image turns grayscale, with no second image to supply
uo_mail.ib_enabled = ib_mail_allowed

Graying is computed automatically: you do not have to supply a second "disabled" image.

Finding out the real size of the image #

// Show the file the user has chosen
uo_preview.is_source = ls_chosen_file
// ue_loaded event of uo_preview : (long al_width, long al_height)
uo_status.of_panel(/*key*/ "main").is_text = String(al_width) + " x " + String(al_height) + " px"

// An image smaller than the frame : do not enlarge it needlessly
if al_width < uo_preview.width and al_height < uo_preview.height then
    uo_preview.is_stretch = uo_preview.STRETCH_NONE
end if

A full-width banner #

// The banner image, filling its strip
uo_banner.is_source  = "img\banniere.jpg"
uo_banner.is_stretch = uo_banner.STRETCH_UNIFORMTOFILL   // fills the whole strip, without distorting
uo_banner.is_valign   = uo_banner.VALIGN_TOP               // keeps the top of the image visible

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