# messagebox — `n_pbt_messagebox` #

← Référence des composants · Sommaire du guide

> Boîte de dialogue modale thémée, à retour synchrone : le remplaçant direct du `MessageBox()` de PowerBuilder, avec texte riche, boutons libres, icônes et case à cocher.

> ▶ Le voir en vrai — Application de démonstration, tuile Message box : l'aperçu, le code qui le produit et cette page, côte à côte.

## En bref #

Objet | `n_pbt_messagebox` — non visuel : rien à poser dans la fenêtre
Sert à | Poser une question ou annoncer un résultat, à la place du `MessageBox()` natif figé et non thémé
Retour | Synchrone : `of_show()` bloque et renvoie l'indice du bouton cliqué

Contrairement aux composants visuels, cet objet ne s'insère pas dans une fenêtre : on le crée, configure, affiche, détruit.

    n_pbt_messagebox lnv_mb

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

## Démarrage rapide #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Suppression"
    lnv_mb.is_icon    = lnv_mb.ICON_WARNING
    lnv_mb.is_message = "Supprimer definitivement [b]12 dossiers[/b] ?[br][br]Cette action est irreversible."

    lnv_mb.of_add_button(/*texte*/ "Supprimer", /*defaut*/ true,  /*annulation*/ false)   // -> 1
    lnv_mb.of_add_button(/*texte*/ "Annuler",   /*defaut*/ false, /*annulation*/ true)    // -> 2

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

    destroy lnv_mb

`of_show` attend la réponse de l'utilisateur : la ligne suivante ne s'exécute qu'après le clic, exactement comme avec `MessageBox()`.

## Propriétés #

À poser avant `of_show`.

Propriété | Type | Défaut | Rôle
--- | --- | --- | ---
`is_title` | string | `""` | Titre affiché dans l'en-tête de la boîte
`is_message` | string | `""` | Corps du message. Accepte le balisage riche (`[b]`, `[i]`, `[br]`, `[accent]`, `[picture=…]`…)
`is_instruction` | string | `""` | Instruction principale : la question elle-même, affichée plus grande au-dessus du message. Titre / instruction / message est l'anatomie qui rend un dialogue lisible d'un coup d'œil — « Supprimer 42 lignes ? » puis « Cette action est définitive » — au lieu d'un bloc uniforme. Accepte le balisage riche
`is_icon` | string | `""` | Icône : une constante `ICON_*`, ou votre propre image (chemin de fichier, ou ressource de DLL `ma.dll:NOM`)
`is_checkbox` | string | `""` | Texte d'une case à cocher optionnelle, style « ne plus me demander » (`""` = pas de case)
`ib_checked` | boolean | `false` | État initial de la case (l'état final se lit avec `of_checked()`)
`ib_input` | boolean | `false` | Ajoute un champ de saisie thématisé (renommer, motif, commentaire), pour qu'une application n'ait plus à bricoler une fenêtre qui ne suit ni le thème ni le sens de lecture. La saisie se relit avec `of_input_value()` après `of_show`. Le tout en un appel : `of_prompt`
`is_input_label` | string | `""` | Libellé au-dessus du champ (`""` = aucun). Nécessite `ib_input`
`is_input_value` | string | `""` | Contenu initial du champ. Il est sélectionné à l'ouverture : taper le remplace, comme dans tout dialogue de renommage
`is_input_placeholder` | string | `""` | Indication affichée tant que le champ est vide. Ce n'est pas une valeur : rien n'est renvoyé si l'utilisateur ne tape rien
`ib_input_password` | boolean | `false` | Masque les caractères saisis
`ib_input_required` | boolean | `false` | Le bouton par défaut reste désactivé tant que le champ est vide. Laisser soumettre pour se faire rabrouer ensuite ne sert personne ; le bouton d'annulation, lui, reste accessible
`ib_buttons_reverse` | boolean | `false` | Ordre des boutons : `false` = de gauche à droite dans l'ordre d'ajout ; `true` = inversé
`is_position` | string | `POSITION_OWNER` | Centrage : `POSITION_OWNER` (sur la fenêtre appelante) ou `POSITION_SCREEN` (sur l'écran)
`il_min_width` | long | `0` | Largeur minimale en pixels (`0` = automatique)
`il_max_width` | long | `0` | Largeur maximale en pixels (`0` = automatique) : le texte revient à la ligne dans cette limite
`il_max_height` | long | `0` | Hauteur maximale en pixels (`0` = automatique) : au-delà, le corps du message défile au lieu d'agrandir la fenêtre

### Constantes #

Constante | Valeur | Usage
--- | --- | ---
`ICON_INFORMATION` | `"information"` | Information neutre
`ICON_WARNING` | `"warning"` | Avertissement, action risquée
`ICON_ERROR` | `"error"` | Échec, erreur
`ICON_QUESTION` | `"question"` | Question fermée
`ICON_SUCCESS` | `"success"` | Confirmation d'un succès
`ICON_NONE` | `"none"` | Aucune icône
`POSITION_OWNER` | `"owner"` | Centré sur la fenêtre appelante
`POSITION_SCREEN` | `"screen"` | Centré sur l'écran

## Méthodes #

Méthode | Rôle
--- | ---
`of_add_button (string as_texte)` → long | Ajoute un bouton simple. Renvoie son indice à partir de 1
`of_add_button (string as_texte, boolean ab_defaut, boolean ab_annulation)` → long | Idem, en marquant le bouton par défaut (Entrée) et/ou d'annulation (Échap)
`of_add_button (string as_texte, string as_icone, boolean ab_defaut, boolean ab_annulation)` → long | Idem, avec une icône sur le bouton
`of_add_button_timed (string as_texte, boolean ab_defaut, boolean ab_annulation, long al_secondes_actif, long al_secondes_clic)` → long | Bouton à compte à rebours : reste désactivé `al_secondes_actif` secondes (compteur visible), puis se clique tout seul au bout de `al_secondes_clic` secondes (`0` = minuteur inactif)
`of_show (long al_hwnd)` → long | Affiche la boîte modale et renvoie l'indice du bouton cliqué (`0` = fermeture par Échap ou par la croix sans bouton d'annulation)
`of_checked ( )` → boolean | État de la case à cocher au moment du dernier `of_show`
`of_input_value ( )` → string | Texte saisi lors du dernier `of_show` (vide si `ib_input` était inactif)
`of_action ( )` → string | Identifiant de la zone `[action=id]` cliquée dans le message, chaîne vide sinon. Une telle zone est un choix proposé dans la phrase même : elle ferme le dialogue et `of_show` renvoie `0`. Une zone `[hyperlink=url]`, elle, s'ouvre dans le navigateur et laisse le dialogue ouvert — l'appelant est bloqué dans `of_show`, un lien ne peut donc pas être une réponse
`of_info (long al_hwnd, string as_titre, string as_message)` → long | Dialogue en une ligne, comme l'est `MessageBox()` : icône d'information et un seul bouton OK, renvoie `1`. Les libellés des boutons viennent des traductions de la bibliothèque (6 langues) au lieu d'être écrits dans chaque application — c'est toute la raison d'être de ces raccourcis
`of_warning (long al_hwnd, string as_titre, string as_message)` → long | Icône d'avertissement, un bouton OK. Renvoie `1`
`of_error (long al_hwnd, string as_titre, string as_message)` → long | Icône d'erreur, un bouton OK. Renvoie `1`
`of_success (long al_hwnd, string as_titre, string as_message)` → long | Icône de réussite, un bouton OK. Renvoie `1`
`of_confirm (long al_hwnd, string as_titre, string as_message)` → long | Question + OK / Annuler. Renvoie `1` = OK, `2` = Annuler, `0` = fermé
`of_yes_no (long al_hwnd, string as_titre, string as_message)` → long | Question + Oui / Non. Renvoie `1` = Oui, `2` = Non, `0` = fermé
`of_yes_no_cancel (long al_hwnd, string as_titre, string as_message)` → long | Question + Oui / Non / Annuler. Renvoie `1`, `2`, `3`, ou `0` si fermé
`of_prompt (long al_hwnd, string as_titre, string as_message, string as_defaut)` → string | Demande une valeur et renvoie ce qui a été saisi, ou une chaîne vide si l'utilisateur a annulé. Pour distinguer une réponse vide d'un abandon, utilisez plutôt `of_show` + `of_input_value`
`of_reset ( )` | Efface toutes les propriétés et les boutons ajoutés : la même instance repart de zéro

Le libellé d'un bouton accepte le balisage riche et le mnémonique `&` (`"&Enregistrer"` souligne le E et l'active par `Alt+E`) ; `&&` affiche une esperluette littérale.

## Le clavier #

Touche | Effet
--- | ---
Entrée | Déclenche le bouton marqué par défaut
Échap | Déclenche le bouton marqué annulation ; sans bouton d'annulation, ferme la boîte et renvoie `0`
Alt + lettre | Déclenche le bouton dont le libellé porte ce mnémonique
Tab | Déplace le focus d'un bouton à l'autre
Ctrl + C | Copie le dialogue (titre, instruction, message, libellés des boutons) dans le presse-papiers, comme toute boîte de dialogue Windows — pratique pour transmettre une erreur au support

> À l'ouverture, aucun bouton n'a de contour de focus : c'est voulu, et c'est le comportement des dialogues Windows modernes. Le liseré n'apparaît qu'après une première pression sur Tab, c'est-à-dire quand l'utilisateur passe explicitement au clavier. Entrée et Échap restent actifs dès la première seconde, même sans focus visible.

## Exemples #

### Question fermée avec bouton par défaut #

    n_pbt_messagebox lnv_mb
    long ll_reponse

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Enregistrer les modifications"
    lnv_mb.is_icon    = lnv_mb.ICON_QUESTION
    lnv_mb.is_message = "Le dossier a ete modifie. Voulez-vous enregistrer avant de fermer ?"

    lnv_mb.of_add_button(/*texte*/ "&Enregistrer",     /*defaut*/ true,  /*annulation*/ false)  // 1
    lnv_mb.of_add_button(/*texte*/ "&Ne pas enregistrer", /*defaut*/ false, /*annulation*/ false) // 2
    lnv_mb.of_add_button(/*texte*/ "Annuler",          /*defaut*/ false, /*annulation*/ 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 ou 0 : on ne ferme pas
    end choose

### Message enrichi et icône #

    lnv_mb.is_title   = "Import termine"
    lnv_mb.is_icon    = lnv_mb.ICON_SUCCESS
    lnv_mb.is_message = "[b]1 240 lignes[/b] integrees.[br][br]" &
                      + "[accent]18 doublons[/accent] ont ete ignores."

    lnv_mb.of_add_button(/*texte*/ "OK", /*defaut*/ true, /*annulation*/ false)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Case « ne plus me demander » #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title    = "Suppression"
    lnv_mb.is_icon     = lnv_mb.ICON_WARNING
    lnv_mb.is_message  = "Supprimer les lignes selectionnees ? Cette action est irreversible."
    lnv_mb.is_checkbox = "Ne plus me demander"
    lnv_mb.ib_checked  = false

    lnv_mb.of_add_button(/*texte*/ "Supprimer", /*defaut*/ true,  /*annulation*/ false)
    lnv_mb.of_add_button(/*texte*/ "Annuler",   /*defaut*/ false, /*annulation*/ true)

    if lnv_mb.of_show(/*hwnd*/ Handle(this)) = 1 then
        of_supprimer()
        // Memoriser le choix de l'utilisateur
        ib_confirmer_suppression = not lnv_mb.of_checked()
    end if

    destroy lnv_mb

### Bouton à compte à rebours #

    lnv_mb.is_title   = "Redemarrage"
    lnv_mb.is_icon    = lnv_mb.ICON_INFORMATION
    lnv_mb.is_message = "L'application va redemarrer pour appliquer la mise a jour."

    // "Continuer" reste grise 3 secondes (un compteur s'affiche)
    lnv_mb.of_add_button_timed(/*texte*/ "Continuer", /*defaut*/ true, /*annulation*/ false, &
                               /*secondes_actif*/ 3, /*secondes_clic*/ 0)

    // "Plus tard" se clique tout seul au bout de 10 secondes
    lnv_mb.of_add_button_timed(/*texte*/ "Plus tard", /*defaut*/ false, /*annulation*/ true, &
                               /*secondes_actif*/ 0, /*secondes_clic*/ 10)

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

### Message long : limiter la taille #

    // Un texte volumineux : la boite est plafonnee et le corps defile
    lnv_mb.is_title      = "Notes de version"
    lnv_mb.is_message    = ls_notes
    lnv_mb.il_max_width  = 480
    lnv_mb.il_max_height = 320

    lnv_mb.of_add_button(/*texte*/ "Fermer", /*defaut*/ true, /*annulation*/ true)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Réutiliser une instance #

    // Une instance de fenetre, plusieurs dialogues : of_reset entre chaque appel
    inv_mb.of_reset()      // efface les proprietes ET les boutons precedents

    inv_mb.is_title   = "Second dialogue"
    inv_mb.is_message = "Chaque of_reset repart d'une boite vierge."
    inv_mb.of_add_button(/*texte*/ "OK", /*defaut*/ true, /*annulation*/ false)
    inv_mb.of_show(/*hwnd*/ Handle(this))

## Bonnes pratiques #

- Toujours `of_reset()` avant de reconfigurer une instance réutilisée : sans cela les boutons du dialogue précédent s'ajoutent aux nouveaux.
- Marquez systématiquement un bouton par défaut et un bouton d'annulation : l'utilisateur au clavier attend Entrée et Échap.
- Testez la valeur de retour `0` : elle signifie que la boîte a été fermée sans choix (croix ou Échap). Traitez-la comme l'annulation.
- Passez `Handle(this)` (ou `Handle(parent)`) comme fenêtre appelante : la boîte se centre dessus et la modalité porte sur la bonne fenêtre.
- Réservez le rouge et `ICON_ERROR` aux vraies erreurs ; une confirmation banale mérite `ICON_QUESTION`.
- Pour une information qui ne demande aucune réponse, préférez une notification non bloquante : voir toaster.

← Référence des composants · Sommaire du guide