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 #
| Userobject | u_pbt_picture |
| Item class | — (component without items) |
| Used for | Replacing a PowerBuilder picture: modern formats (SVG, WebP, animated GIF), controlled framing, clickable image, automatic graying |
| Opt-in options | ib_zoomable · ib_clickable · ib_allow_drop · ib_auto_height · ib_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:
| Form | Example | Use |
|---|---|---|
| Local file | img\logo.png | png, jpg, jfif, bmp, gif, ico, svg, webp, avif — and tif, tiff, wmf, emf, rle, converted on the fly |
| Web address | https://…/logo.png | Image loaded from a server (https only: an http:// address is refused, see below) |
| Embedded data | data:image/png;base64,… | Image already in memory, with no intermediate file |
| DLL resource | img\packimages.dll:SAMPLE | Image 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.
The formats of the native Picture that the engine does not read — TIFF (scans, faxes), WMF, EMF and RLE — are converted on the fly: an application brought over from PowerBuilder keeps its pictures. Blanks around a path are ignored: a CHAR column read by GetItemString arrives padded with spaces, and Windows ignores them too; is_source reads back as you wrote it. A recoloured picture (mono:, tint:) served by another site over https is drawn only when that server allows cross-origin requests (the Access-Control-Allow-Origin header); otherwise ue_error says so (REASON_FAILED). Files of the workstation, DLL resources and data: are not concerned.
A picture in memory — a photo stored in the database and read by SelectBlob — is shown by of_set_picture(blob), like SetPicture of the native Picture: no temporary file, no base64. The format is recognised from the bytes; ue_loaded or ue_error follow, as for is_source.
How it is framed: is_stretch #
| Constant | Effect |
|---|---|
STRETCH_UNIFORM | Default. The image is scaled without distortion and stays fully visible; margins may appear |
STRETCH_UNIFORMTOFILL | Scaled without distortion, but the frame is filled completely; anything overflowing is cropped |
STRETCH_FILL | The image is stretched to fit the frame exactly — it may be distorted |
STRETCH_NONE | Original 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 #
| Constant | Value | For |
|---|---|---|
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_270 | 0 90 180 270 | ii_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 #
| Property | Type | Default | Purpose |
|---|---|---|---|
is_source | string | "" | The image to display (see the four forms above) |
is_stretch | string | "uniform" | Framing mode: STRETCH_NONE, STRETCH_FILL, STRETCH_UNIFORM, STRETCH_UNIFORMTOFILL |
is_align | string | "center" | Horizontal placement when the image is smaller than the control: ALIGN_CENTER, ALIGN_START, ALIGN_END. The vertical axis is is_valign |
is_valign | string | "center" | Vertical 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_enabled | boolean | true | When false, the image is displayed in grayscale and answers nothing: clicks, wheel, keyboard and file drops |
ii_badge | integer | 0 | Counter 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). Beyond 99 it shows 99+; a screen reader hears it with the picture ("Mailbox, 5 new") |
il_badge_color | long | -1 | Badge 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_size | integer | 0 | Badge 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_mouse | boolean | false | Opt-in: enables ue_mouse_enter / ue_mouse_leave |
is_placeholder | string | "" | 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_source | string | "" | 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_rotation | integer | 0 | Quarter 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_mirror | boolean | false | Horizontal mirror on screen: the picture is flipped left to right, whatever ii_rotation |
ib_zoomable | boolean | false | Opt-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 the key marked 0, whatever the keyboard layout); the 1 key shows the picture at its ACTUAL size, one pixel of the picture for one pixel of the screen. With Ctrl or Alt held down, these keys are left to your application. 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_zoom | double | 1.0 | Zoom 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, this property set by your code, or a new source bringing it back to 1.0). Needs ib_zoomable, set first: without it the factor stays 1.0. Set it after is_source: a new picture starts at the fitted view |
id_max_zoom | double | 8.0 | The CEILING of the zoom, in the unit of id_zoom (1.0 = the fitted view): the wheel, the + key and id_zoom stop there, whatever the size of the picture. Any value from 1.0; under it, the default comes back. Only the 1 key goes beyond, to the ACTUAL size — a large scan shown small remains readable pixel for pixel; from there, + does nothing and - comes back down. Lowered under the current zoom, the zoom comes down to it and ue_zoom_changed says so |
ib_allow_drop | boolean | false | Opt-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_height | boolean | false | Opt-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_text | string | "" | Text alternative: what a screen reader says of the picture, followed by the count of the badge, or by "Picture unavailable" when the source failed. Leave it empty for a purely decorative picture |
ib_clickable | boolean | false | Opt-in: the picture is a BUTTON — in the Tab order, with a visible focus ring, and Enter or Space raise ue_clicked like a click (the window's Default button does not answer then). Disabled, it leaves the Tab order. A screen reader announces a button named by is_alt_text. Without it, a picture is an image: Enter goes on to the window |
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) |
is_tooltip | string | "" | Simple tooltip shown when hovering the component |
is_super_tooltip_title | string | "" | Title of the rich tooltip (takes precedence over is_tooltip) |
is_super_tooltip_text | string | "" | Text of the rich tooltip (rich markup accepted) |
is_super_tooltip_image | string | "" | Image of the rich tooltip |
Methods #
| Method | Purpose |
|---|---|
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_picture (blob ablb_image) | Shows a picture held in memory — a photo read from the database by SelectBlob — like SetPicture of the native Picture: no temporary file, no base64. The format is recognised from the bytes (tif, wmf and emf converted); is_source then reads back the address the picture is served at, and ue_loaded or ue_error follow. Returns 0 once handed over, -5 when the blob is empty or not a picture, -4 beyond 32 MB, -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 #
| Event | Raised when |
|---|---|
ue_clicked ( ) | Left click on the image — or Enter / Space with ib_clickable. 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. For an SVG they are the dimensions it declares (width, height); an SVG drawn at 100 % declares none, and the engine gives it a default box (150 pixels high, the proportions of its drawing): the ratio is right, the size means nothing |
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 +, -, 0 and 1 keys, id_zoom or a lower id_max_zoom set by your code, a new is_source or ib_zoomable turned off (back to 1.0) — nothing when the factor stays the same, nor on of_reset. 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 #
// rowfocuschanged event of dw_customer : show the photo of the current customer
// Local variables
string ls_customer_code
// The code of the customer on the new row
if currentrow < 1 then return
ls_customer_code = this.GetItemString(currentrow, "customer_code")
// The photo fills its frame ; the blanks padding a CHAR column are ignored
uo_photo.is_source = "photos\" + ls_customer_code + ".jpg"
uo_photo.is_stretch = uo_photo.STRETCH_UNIFORMTOFILL
// Once, in the open event of the window : the picture shown when a photo is missing
uo_photo.is_error_source = "img\photo_missing.svg"
// ue_error event of uo_photo : (string as_message, string as_reason)
// The fallback picture already shows : here, only count the missing photos
if as_reason = uo_photo.REASON_NOT_FOUND then
il_missing_photos = il_missing_photos + 1
end if
is_error_source is the right way to deal with a missing photo: there is no need to test whether the file exists before assigning it. Never reassign is_source from ue_error: if the replacement were missing in its turn, the failure would start the load again, endlessly.
Showing a photo stored in the database #
// Local variables
blob lb_photo
// The photo of the employee, stored in a column of the database
SELECTBLOB photo INTO :lb_photo FROM employee WHERE emp_id = 4152 USING SQLCA;
// Shown straight from memory : 0 = handed over, -5 = not a picture
if uo_photo.of_set_picture(/*image*/ lb_photo) <> 0 then
uo_photo.is_source = ""
end if
A clickable image, button-style #
// The picture, its name for the keyboard and screen readers, and its tooltip
uo_avatar.is_source = "photos\user.png"
uo_avatar.is_alt_text = "My account"
uo_avatar.is_tooltip = "My account"
// A button for the keyboard too : Tab reaches it, Enter or Space raise ue_clicked
uo_avatar.ib_clickable = true
// ue_clicked event of uo_avatar
of_open_my_account()
Counter and graying #
// Local variables
long ll_unread
// A notification badge on a mail icon
ll_unread = 7
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 #
// Local variables
string ls_chosen_file, ls_name
// Show the file the user has chosen
if GetFileOpenName("Picture", ls_chosen_file, ls_name, "jpg", "Pictures (*.jpg;*.png),*.jpg;*.png", /*initdir*/ "", OFN_EXPLORER + OFN_NOCHANGEDIR) = 1 then
uo_preview.is_source = ls_chosen_file
end if
// 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. The size of the picture
// is in PIXELS, the one of the userobject in PowerBuilder units : compare them in one unit
if al_width < UnitsToPixels(uo_preview.width, XUnitsToPixels!) and al_height < UnitsToPixels(uo_preview.height, YUnitsToPixels!) 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 #
STRETCH_UNIFORMis the safe mode: it never distorts. SaveSTRETCH_FILLfor decorative backgrounds where distortion does not matter.- For a photo in a fixed frame (staff directory, thumbnail),
STRETCH_UNIFORMTOFILLgives a consistent result, with no unsightly margins. - Bundle your icons in a resource DLL rather than shipping hundreds of files; the
pack.dll:TYPE/NAMEform removes any ambiguity. - For a monochrome glyph that has to follow the light and dark themes, use the
mono:prefix (Images and icons). - Give an
is_error_sourceto any image whose source depends on data, and keepue_errorfor your log: never reassignis_sourcethere. - Set
id_zoomafteris_source: a new picture starts at the fitted view. - Call
of_reset()before reusing the component for a different kind of image: otherwise the previous framing mode, badge or grayed-out state stays in place.
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 |
is_accessible_name · is_accessible_description | The name and description a screen reader says | 3.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.