# messagebox — `n_pbt_messagebox` #

← Component reference · Guide contents

> Themed modal dialog box with a synchronous return value: the drop-in replacement for PowerBuilder's `MessageBox()`, with rich text, free-form buttons, icons and a check box.

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

## At a glance #

Object | `n_pbt_messagebox` — non-visual: nothing to place in the window
Used for | Asking a question or announcing a result, instead of the rigid, unthemed native `MessageBox()`
Return value | Synchronous: `of_show()` blocks and returns the index of the button that was clicked

Unlike the visual components, this object is not dropped into a window: you create, configure, show, destroy it.

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox
    // ... configuration ...
    destroy lnv_mb

## Quick start #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Deletion"
    lnv_mb.is_icon    = lnv_mb.ICON_WARNING
    lnv_mb.is_message = "Permanently delete [b]12 folders[/b] ?[br][br]This action cannot be undone."

    lnv_mb.of_add_button(/*text*/ "Delete", /*default*/ true,  /*cancel*/ false)   // -> 1
    lnv_mb.of_add_button(/*text*/ "Cancel",   /*default*/ false, /*cancel*/ true)    // -> 2

    if lnv_mb.of_show(/*hwnd*/ Handle(this)) = 1 then
        of_supprimer()
    end if

    destroy lnv_mb

`of_show` waits for the user's answer: the next line only runs after the click, exactly as with `MessageBox()`.

## Properties #

To be set before `of_show`.

Property | Type | Default | Purpose
--- | --- | --- | ---
`is_title` | string | `""` | Title displayed in the header of the box
`is_message` | string | `""` | Body of the message. Accepts rich text markup (`[b]`, `[i]`, `[br]`, `[accent]`, `[picture=…]`…)
`is_instruction` | string | `""` | Main instruction: the question itself, shown bigger above the message. Title / instruction / message is the anatomy that makes a dialog readable at a glance — "Delete 42 rows?" then "This cannot be undone" — instead of one uniform block. Accepts the rich markup
`is_icon` | string | `""` | Icon: an `ICON_*` constant, or your own image (file path, or DLL resource `my.dll:NAME`)
`is_checkbox` | string | `""` | Text of an optional check box, "don't ask me again" style (`""` = no check box)
`ib_checked` | boolean | `false` | Initial state of the check box (the final state is read with `of_checked()`)
`ib_input` | boolean | `false` | Adds a themed input field (rename, reason, comment), so an application no longer needs a hand-built window that follows neither the theme nor the reading direction. Read it back with `of_input_value()` after `of_show`. The whole thing in one call: `of_prompt`
`is_input_label` | string | `""` | Label above the field (`""` = none). Needs `ib_input`
`is_input_value` | string | `""` | Initial content of the field. It is selected when the dialog opens: typing replaces it, as in every rename dialog
`is_input_placeholder` | string | `""` | Hint shown while the field is empty. It is not a value: nothing is returned if the user types nothing
`ib_input_password` | boolean | `false` | Masks the characters typed
`ib_input_required` | boolean | `false` | The default button stays disabled while the field is empty. Letting the user submit only to be told off afterwards serves nobody; the cancel button stays reachable
`ib_buttons_reverse` | boolean | `false` | Button order: `false` = left to right in the order they were added; `true` = reversed
`is_position` | string | `POSITION_OWNER` | Centering: `POSITION_OWNER` (on the calling window) or `POSITION_SCREEN` (on the screen)
`il_min_width` | long | `0` | Minimum width in pixels (`0` = automatic)
`il_max_width` | long | `0` | Maximum width in pixels (`0` = automatic): the text wraps within that limit
`il_max_height` | long | `0` | Maximum height in pixels (`0` = automatic): beyond it, the body of the message scrolls instead of growing the window

### Constants #

Constant | Value | Use
--- | --- | ---
`ICON_INFORMATION` | `"information"` | Neutral information
`ICON_WARNING` | `"warning"` | Warning, risky action
`ICON_ERROR` | `"error"` | Failure, error
`ICON_QUESTION` | `"question"` | Closed question
`ICON_SUCCESS` | `"success"` | Confirmation of a success
`ICON_NONE` | `"none"` | No icon
`POSITION_OWNER` | `"owner"` | Centered on the calling window
`POSITION_SCREEN` | `"screen"` | Centered on the screen

## Methods #

Method | Purpose
--- | ---
`of_add_button (string as_texte)` → long | Adds a plain button. Returns its index, starting at 1
`of_add_button (string as_texte, boolean ab_defaut, boolean ab_annulation)` → long | Same thing, marking the button as the default one (Enter) and/or the cancel one (Esc)
`of_add_button (string as_texte, string as_icone, boolean ab_defaut, boolean ab_annulation)` → long | Same thing, with an icon on the button
`of_add_button_timed (string as_texte, boolean ab_defaut, boolean ab_annulation, long al_secondes_actif, long al_secondes_clic)` → long | Countdown button: stays disabled for `al_secondes_actif` seconds (with a visible counter), then clicks itself after `al_secondes_clic` seconds (`0` = timer off)
`of_show (long al_hwnd)` → long | Shows the modal box and returns the index of the button that was clicked (`0` = closed with Esc or the X, with no cancel button)
`of_checked ( )` → boolean | State of the check box as of the last `of_show`
`of_input_value ( )` → string | Text typed during the last `of_show` (empty when `ib_input` was off)
`of_action ( )` → string | Id of the `[action=id]` zone clicked inside the message, an empty string otherwise. Such a zone is a choice offered in the sentence itself: it closes the dialog and `of_show` returns `0`. A `[hyperlink=url]` zone, on the other hand, opens in the browser and leaves the dialog up — the caller is blocked inside `of_show`, so a link cannot be an answer
`of_info (long al_hwnd, string as_title, string as_message)` → long | One-line dialog, the way `MessageBox()` is one: information icon and a single OK button, returns `1`. The button labels come from the library's own translations (6 languages) instead of being written in each application — which is the whole reason these shortcuts exist
`of_warning (long al_hwnd, string as_title, string as_message)` → long | Warning icon, one OK button. Returns `1`
`of_error (long al_hwnd, string as_title, string as_message)` → long | Error icon, one OK button. Returns `1`
`of_success (long al_hwnd, string as_title, string as_message)` → long | Success icon, one OK button. Returns `1`
`of_confirm (long al_hwnd, string as_title, string as_message)` → long | Question + OK / Cancel. Returns `1` = OK, `2` = Cancel, `0` = dismissed
`of_yes_no (long al_hwnd, string as_title, string as_message)` → long | Question + Yes / No. Returns `1` = Yes, `2` = No, `0` = dismissed
`of_yes_no_cancel (long al_hwnd, string as_title, string as_message)` → long | Question + Yes / No / Cancel. Returns `1`, `2`, `3`, or `0` when dismissed
`of_prompt (long al_hwnd, string as_title, string as_message, string as_default)` → string | Asks for a value and returns what was typed, or an empty string when the user cancelled. To tell an empty answer from a cancel, use `of_show` + `of_input_value` instead
`of_reset ( )` | Clears every property and the buttons that were added: the same instance starts over from scratch

A button label accepts rich text markup and the `&` mnemonic (`"&Save"` underlines the S and activates the button with `Alt+S`); `&&` displays a literal ampersand.

## The keyboard #

Key | Effect
--- | ---
Enter | Triggers the button marked as default
Esc | Triggers the button marked as cancel; with no cancel button, closes the box and returns `0`
Alt + letter | Triggers the button whose label carries that mnemonic
Tab | Moves the focus from one button to the next
Ctrl + C | Copies the dialog (title, instruction, message, button labels) to the clipboard, like every Windows dialog — handy when an error has to be forwarded to support

> When the box opens, no button shows a focus outline: this is intentional, and it is how modern Windows dialogs behave. The outline only appears after the first press on Tab, that is, once the user explicitly switches to the keyboard. Enter and Esc remain active from the very first second, even with no visible focus.

## Examples #

### Closed question with a default button #

    n_pbt_messagebox lnv_mb
    long ll_reponse

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Save changes"
    lnv_mb.is_icon    = lnv_mb.ICON_QUESTION
    lnv_mb.is_message = "The folder has been modified. Do you want to save before closing ?"

    lnv_mb.of_add_button(/*text*/ "&Save",     /*default*/ true,  /*cancel*/ false)  // 1
    lnv_mb.of_add_button(/*text*/ "Do &not save", /*default*/ false, /*cancel*/ false) // 2
    lnv_mb.of_add_button(/*text*/ "Cancel",          /*default*/ false, /*cancel*/ true)   // 3

    ll_reponse = lnv_mb.of_show(/*hwnd*/ Handle(this))
    destroy lnv_mb

    choose case ll_reponse
        case 1 ; of_enregistrer() ; Close(parent)
        case 2 ; Close(parent)
        case else ; // 3 or 0 : do not close
    end choose

### Rich message and icon #

    lnv_mb.is_title   = "Import complete"
    lnv_mb.is_icon    = lnv_mb.ICON_SUCCESS
    lnv_mb.is_message = "[b]1,240 rows[/b] imported.[br][br]" &
                      + "[accent]18 duplicates[/accent] were skipped."

    lnv_mb.of_add_button(/*text*/ "OK", /*default*/ true, /*cancel*/ false)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### A "don't ask me again" check box #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title    = "Deletion"
    lnv_mb.is_icon     = lnv_mb.ICON_WARNING
    lnv_mb.is_message  = "Delete the selected rows ? This action cannot be undone."
    lnv_mb.is_checkbox = "Don't ask me again"
    lnv_mb.ib_checked  = false

    lnv_mb.of_add_button(/*text*/ "Delete", /*default*/ true,  /*cancel*/ false)
    lnv_mb.of_add_button(/*text*/ "Cancel",   /*default*/ false, /*cancel*/ true)

    if lnv_mb.of_show(/*hwnd*/ Handle(this)) = 1 then
        of_supprimer()
        // Remember the user choice
        ib_confirmer_suppression = not lnv_mb.of_checked()
    end if

    destroy lnv_mb

### Countdown button #

    lnv_mb.is_title   = "Restart"
    lnv_mb.is_icon    = lnv_mb.ICON_INFORMATION
    lnv_mb.is_message = "The application will restart to apply the update."

    // "Continue" stays grayed out for 3 seconds (a counter is displayed)
    lnv_mb.of_add_button_timed(/*text*/ "Continue", /*default*/ true, /*cancel*/ false, &
                               /*active_seconds*/ 3, /*click_seconds*/ 0)

    // "Later" clicks itself after 10 seconds
    lnv_mb.of_add_button_timed(/*text*/ "Later", /*default*/ false, /*cancel*/ true, &
                               /*active_seconds*/ 0, /*click_seconds*/ 10)

    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Long message: capping the size #

    // A large body of text : the box is capped and the body scrolls
    lnv_mb.is_title      = "Release notes"
    lnv_mb.is_message    = ls_notes
    lnv_mb.il_max_width  = 480
    lnv_mb.il_max_height = 320

    lnv_mb.of_add_button(/*text*/ "Close", /*default*/ true, /*cancel*/ true)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Reusing an instance #

    // One window instance, several dialogs : of_reset between each call
    inv_mb.of_reset()      // clears the properties AND the previous buttons

    inv_mb.is_title   = "Second dialog"
    inv_mb.is_message = "Every of_reset starts over from a blank box."
    inv_mb.of_add_button(/*text*/ "OK", /*default*/ true, /*cancel*/ false)
    inv_mb.of_show(/*hwnd*/ Handle(this))

## Best practices #

- Always call `of_reset()` before reconfiguring a reused instance: without it, the buttons of the previous dialog are added to the new ones.
- Systematically mark one default button and one cancel button: keyboard users expect Enter and Esc to work.
- Test for the return value `0`: it means the box was closed without a choice (the X or Esc). Treat it as a cancellation.
- Pass `Handle(this)` (or `Handle(parent)`) as the calling window: the box centers on it and the modality applies to the right window.
- Save red and `ICON_ERROR` for genuine errors; a routine confirmation deserves `ICON_QUESTION`.
- For information that needs no answer at all, prefer a non-blocking notification: see toaster.

← Component reference · Guide contents