# 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_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, bmp, gif, ico, svg, webp
Web address | `https://…/logo.png` | Image loaded from a server (`http` or `https`)
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.

## 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`.

## 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`
`is_valign` | string | `VALIGN_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
`ROTATION_NONE` · `ROTATION_90` · `ROTATION_180` · `ROTATION_270` | `0` `90` `180` `270` | `ii_rotation`

`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`
`ib_enabled` | boolean | `true` | When `false`, the image is displayed in grayscale
`ii_badge` | integer | `0` | Counter badge in the upper-right corner (`0` = none)
`il_badge_color` | long | `0` | Badge background, as a PowerBuilder RGB value (`0` = the color that comes from the theme). 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, applied on top of the rotation
`ib_zoomable` | boolean | `false` | Opt-in: the user may come closer (wheel), move around (drag) and go back to the fitted view (double click). 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` means the whole picture fits, up to `8.0`. Reading it back gives the current factor, wheel included (`ue_zoom_changed` tells you at every step). Needs `ib_zoomable`
`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
`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_theme_style` | string | `fluent` | Visual style of the component (`THEME_STYLE_*` constants)
`is_theme_mode` | string | `light` | Light or dark variant (`THEME_MODE_*` constants)
`il_theme_accent` | long | `-1` | Accent color of this component (`-1` = the theme accent)
`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
`of_set_redraw (boolean)` | Groups a burst of changes into a single render
`of_save_as_png (string)` · `of_save_as_jpg (string)` | Exports the rendering as an image

## Events #

Event | Raised when
--- | ---
`ue_clicked ( )` | Left click on the image
`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)` | The image could not be loaded (missing file, unreachable address, rejected format)
`ue_rclicked ( )` | Right click on the image
`ue_double_clicked ( )` | Double click on the image. The single clicks that precede it are raised too, in the same order. 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, whether from the wheel or from `id_zoom`. `1.0` means the whole picture fits again
`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_code_client + ".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)
    uo_photo.is_source = "img\photo_absente.svg"     // fallback image

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 #

    uo_avatar.is_source    = "photos\utilisateur.png"
    uo_avatar.is_tooltip   = "My account"

    // ue_clicked event of uo_avatar
    of_ouvrir_mon_compte()

### Counter and graying #

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

    // Red beyond a threshold, theme color otherwise (0)
    if ll_non_lus > 20 then
        uo_messagerie.il_badge_color = RGB(200, 30, 30)
    else
        uo_messagerie.il_badge_color = 0
    end if

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

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

### Finding out the real size of the image #

    uo_apercu.is_source = ls_fichier_choisi

    // ue_loaded event of uo_apercu : (long al_width, long al_height)
    uo_statut.of_item("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_apercu.width and al_height < uo_apercu.height then
        uo_apercu.is_stretch = uo_apercu.STRETCH_NONE
    end if

### A full-width banner #

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

## Best practices #

- `STRETCH_UNIFORM` is the safe mode: it never distorts. Save `STRETCH_FILL` for decorative backgrounds where distortion does not matter.
- For a photo in a fixed frame (staff directory, thumbnail), `STRETCH_UNIFORMTOFILL` gives a consistent result, with no unsightly margins.
- Bundle your icons in a resource DLL rather than shipping hundreds of files; the `pack.dll:TYPE/NAME` form removes any ambiguity.
- For a monochrome glyph that has to follow the light and dark themes, use the `mono:` prefix (Images and icons).
- Script `ue_error` on any image whose source depends on data: it is your only safety net when a file is missing.
- 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.

← Component reference · Guide contents