# messagebox — `n_pbt_messagebox` #

← Referência dos componentes · Índice do guia

> Caixa de diálogo modal com tema, de retorno síncrono: o substituto direto do `MessageBox()` do PowerBuilder, com texto formatado, botões livres, ícones e caixa de verificação.

> ▶ Ver ao vivo — Aplicação de demonstração, mosaico Message box: a pré-visualização, o código que o produz e esta página, lado a lado.

## Em resumo #

Objeto | `n_pbt_messagebox` — não visual: nada a colocar na janela
Serve para | Colocar uma questão ou anunciar um resultado, em vez do `MessageBox()` nativo, rígido e sem tema
Retorno | Síncrono: `of_show()` bloqueia e devolve o índice do botão clicado

Ao contrário dos componentes visuais, este objeto não se insere numa janela: cria-se, configura-se, apresenta-se, destrói-se.

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox
    // ... configuracao ...
    destroy lnv_mb

## Início rápido #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Eliminação"
    lnv_mb.is_icon    = lnv_mb.ICON_WARNING
    lnv_mb.is_message = "Eliminar definitivamente [b]12 processos[/b]?[br][br]Esta ação é irreversível."

    lnv_mb.of_add_button(/*texto*/ "Eliminar", /*predefinido*/ true,  /*cancelamento*/ false)   // -> 1
    lnv_mb.of_add_button(/*texto*/ "Cancelar", /*predefinido*/ false, /*cancelamento*/ true)    // -> 2

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

    destroy lnv_mb

`of_show` aguarda a resposta do utilizador: a linha seguinte só é executada após o clique, exatamente como acontece com `MessageBox()`.

## Propriedades #

A definir antes de `of_show`.

Propriedade | Tipo | Predefinição | Função
--- | --- | --- | ---
`is_title` | string | `""` | Título apresentado no cabeçalho da caixa
`is_message` | string | `""` | Corpo da mensagem. Aceita o texto formatado com etiquetas (`[b]`, `[i]`, `[br]`, `[accent]`, `[picture=…]`…)
`is_instruction` | string | `""` | Instrução principal: a pergunta em si, apresentada maior acima da mensagem. Título / instrução / mensagem é a anatomia que torna um diálogo legível de relance — «Eliminar 42 linhas?» e depois «Esta ação é definitiva» — em vez de um bloco uniforme. Aceita a marcação
`is_icon` | string | `""` | Ícone: uma constante `ICON_*`, ou uma imagem própria (caminho de ficheiro, ou recurso de DLL `ma.dll:NOM`)
`is_checkbox` | string | `""` | Texto de uma caixa de verificação opcional, do género «não voltar a perguntar» (`""` = sem caixa)
`ib_checked` | boolean | `false` | Estado inicial da caixa (o estado final lê-se com `of_checked()`)
`ib_input` | boolean | `false` | Acrescenta um campo de entrada com o tema aplicado (mudar o nome, motivo, comentário), para que uma aplicação já não precise de uma janela feita à mão que não segue nem o tema nem o sentido de leitura. Relê-se com `of_input_value()` após `of_show`. Tudo numa chamada: `of_prompt`
`is_input_label` | string | `""` | Etiqueta por cima do campo (`""` = nenhuma). Requer `ib_input`
`is_input_value` | string | `""` | Conteúdo inicial do campo. Está selecionado na abertura: escrever substitui-o, como em qualquer diálogo de mudança de nome
`is_input_placeholder` | string | `""` | Indicação apresentada enquanto o campo estiver vazio. Não é um valor: se o utilizador nada escrever, nada é devolvido
`ib_input_password` | boolean | `false` | Oculta os carateres escritos
`ib_input_required` | boolean | `false` | O botão predefinido mantém-se desativado enquanto o campo estiver vazio. Deixar submeter para depois repreender não serve a ninguém; o botão de cancelar continua acessível
`ib_buttons_reverse` | boolean | `false` | Ordem dos botões: `false` = da esquerda para a direita, pela ordem de adição; `true` = invertida
`is_position` | string | `POSITION_OWNER` | Centragem: `POSITION_OWNER` (na janela chamadora) ou `POSITION_SCREEN` (no ecrã)
`il_min_width` | long | `0` | Largura mínima em píxeis (`0` = automática)
`il_max_width` | long | `0` | Largura máxima em píxeis (`0` = automática): o texto muda de linha dentro deste limite
`il_max_height` | long | `0` | Altura máxima em píxeis (`0` = automática): para além disso, o corpo da mensagem desloca-se em vez de aumentar a janela

### Constantes #

Constante | Valor | Utilização
--- | --- | ---
`ICON_INFORMATION` | `"information"` | Informação neutra
`ICON_WARNING` | `"warning"` | Aviso, ação arriscada
`ICON_ERROR` | `"error"` | Falha, erro
`ICON_QUESTION` | `"question"` | Questão fechada
`ICON_SUCCESS` | `"success"` | Confirmação de um êxito
`ICON_NONE` | `"none"` | Nenhum ícone
`POSITION_OWNER` | `"owner"` | Centrada na janela chamadora
`POSITION_SCREEN` | `"screen"` | Centrada no ecrã

## Métodos #

Método | Função
--- | ---
`of_add_button (string as_texte)` → long | Adiciona um botão simples. Devolve o respetivo índice a partir de 1
`of_add_button (string as_texte, boolean ab_defaut, boolean ab_annulation)` → long | O mesmo, marcando o botão predefinido (Enter) e/ou de cancelamento (Esc)
`of_add_button (string as_texte, string as_icone, boolean ab_defaut, boolean ab_annulation)` → long | O mesmo, com um ícone no botão
`of_add_button_timed (string as_texte, boolean ab_defaut, boolean ab_annulation, long al_secondes_actif, long al_secondes_clic)` → long | Botão com contagem decrescente: permanece desativado durante `al_secondes_actif` segundos (contador visível) e depois clica-se sozinho ao fim de `al_secondes_clic` segundos (`0` = temporizador inativo)
`of_show (long al_hwnd)` → long | Apresenta a caixa modal e devolve o índice do botão clicado (`0` = fecho por Esc ou pela cruz, sem botão de cancelamento)
`of_checked ( )` → boolean | Estado da caixa de verificação no momento do último `of_show`
`of_input_value ( )` → string | Texto escrito no último `of_show` (vazio se `ib_input` estava desativado)
`of_action ( )` → string | Id da zona `[action=id]` clicada na mensagem, cadeia vazia caso contrário. Uma zona destas é uma escolha oferecida na própria frase: fecha o diálogo e `of_show` devolve `0`. Já uma zona `[hyperlink=url]` abre no navegador e deixa o diálogo aberto — quem chamou está bloqueado em `of_show`, pelo que uma ligação não pode ser uma resposta
`of_info (long al_hwnd, string as_title, string as_message)` → long | Diálogo numa linha, tal como `MessageBox()` o é: ícone de informação e um único botão OK, devolve `1`. As etiquetas vêm das traduções da biblioteca (6 idiomas) em vez de serem escritas em cada aplicação — é toda a razão de ser destes atalhos
`of_warning (long al_hwnd, string as_title, string as_message)` → long | Ícone de aviso, um botão OK. Devolve `1`
`of_error (long al_hwnd, string as_title, string as_message)` → long | Ícone de erro, um botão OK. Devolve `1`
`of_success (long al_hwnd, string as_title, string as_message)` → long | Ícone de êxito, um botão OK. Devolve `1`
`of_confirm (long al_hwnd, string as_title, string as_message)` → long | Pergunta + OK / Cancelar. Devolve `1` = OK, `2` = Cancelar, `0` = fechado
`of_yes_no (long al_hwnd, string as_title, string as_message)` → long | Pergunta + Sim / Não. Devolve `1` = Sim, `2` = Não, `0` = fechado
`of_yes_no_cancel (long al_hwnd, string as_title, string as_message)` → long | Pergunta + Sim / Não / Cancelar. Devolve `1`, `2`, `3`, ou `0` se fechado
`of_prompt (long al_hwnd, string as_title, string as_message, string as_default)` → string | Pede um valor e devolve o que foi escrito, ou uma cadeia vazia se o utilizador cancelou. Para distinguir uma resposta vazia de um cancelamento, use `of_show` + `of_input_value`
`of_reset ( )` | Limpa todas as propriedades e os botões adicionados: a mesma instância recomeça do zero

A etiqueta de um botão aceita o texto formatado com etiquetas e o mnemónico `&` (`"&Guardar"` sublinha o G e ativa-o com `Alt+G`); `&&` apresenta um E comercial literal.

## O teclado #

Tecla | Efeito
--- | ---
Enter | Aciona o botão marcado como predefinido
Esc | Aciona o botão marcado como cancelamento; sem botão de cancelamento, fecha a caixa e devolve `0`
Alt + letra | Aciona o botão cuja etiqueta contém esse mnemónico
Tab | Desloca o foco de um botão para outro
Ctrl + C | Copia o diálogo (título, instrução, mensagem, etiquetas dos botões) para a área de transferência, como qualquer caixa de diálogo do Windows — prático quando um erro tem de ser encaminhado para o suporte

> Na abertura, nenhum botão tem contorno de foco: é intencional e corresponde ao comportamento das caixas de diálogo modernas do Windows. O contorno só aparece após uma primeira pressão em Tab, ou seja, quando o utilizador passa explicitamente para o teclado. Enter e Esc permanecem ativos desde o primeiro segundo, mesmo sem foco visível.

## Exemplos #

### Questão fechada com botão predefinido #

    n_pbt_messagebox lnv_mb
    long ll_reponse

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title   = "Guardar as alterações"
    lnv_mb.is_icon    = lnv_mb.ICON_QUESTION
    lnv_mb.is_message = "O processo foi modificado. Pretende guardar antes de fechar?"

    lnv_mb.of_add_button(/*texto*/ "&Guardar",     /*predefinido*/ true,  /*cancelamento*/ false)  // 1
    lnv_mb.of_add_button(/*texto*/ "&Não guardar", /*predefinido*/ false, /*cancelamento*/ false) // 2
    lnv_mb.of_add_button(/*texto*/ "Cancelar",          /*predefinido*/ false, /*cancelamento*/ 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: nao se fecha
    end choose

### Mensagem enriquecida e ícone #

    lnv_mb.is_title   = "Importação concluída"
    lnv_mb.is_icon    = lnv_mb.ICON_SUCCESS
    lnv_mb.is_message = "[b]1 240 linhas[/b] integradas.[br][br]" &
                      + "[accent]18 duplicados[/accent] foram ignorados."

    lnv_mb.of_add_button(/*texto*/ "OK", /*predefinido*/ true, /*cancelamento*/ false)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Caixa «não voltar a perguntar» #

    n_pbt_messagebox lnv_mb

    lnv_mb = create n_pbt_messagebox

    lnv_mb.is_title    = "Eliminação"
    lnv_mb.is_icon     = lnv_mb.ICON_WARNING
    lnv_mb.is_message  = "Eliminar as linhas selecionadas? Esta ação é irreversível."
    lnv_mb.is_checkbox = "Não voltar a perguntar"
    lnv_mb.ib_checked  = false

    lnv_mb.of_add_button(/*texto*/ "Eliminar", /*predefinido*/ true,  /*cancelamento*/ false)
    lnv_mb.of_add_button(/*texto*/ "Cancelar", /*predefinido*/ false, /*cancelamento*/ true)

    if lnv_mb.of_show(/*hwnd*/ Handle(this)) = 1 then
        of_supprimer()
        // Memorizar a escolha do utilizador
        ib_confirmer_suppression = not lnv_mb.of_checked()
    end if

    destroy lnv_mb

### Botão com contagem decrescente #

    lnv_mb.is_title   = "Reinício"
    lnv_mb.is_icon    = lnv_mb.ICON_INFORMATION
    lnv_mb.is_message = "A aplicação vai reiniciar para aplicar a atualização."

    // "Continuar" permanece esbatido durante 3 segundos (e apresentado um contador)
    lnv_mb.of_add_button_timed(/*texto*/ "Continuar", /*predefinido*/ true, /*cancelamento*/ false, &
                               /*segundos_ativo*/ 3, /*segundos_clique*/ 0)

    // "Mais tarde" clica-se sozinho ao fim de 10 segundos
    lnv_mb.of_add_button_timed(/*texto*/ "Mais tarde", /*predefinido*/ false, /*cancelamento*/ true, &
                               /*segundos_ativo*/ 0, /*segundos_clique*/ 10)

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

### Mensagem longa: limitar o tamanho #

    // Um texto volumoso: a caixa e limitada e o corpo desloca-se
    lnv_mb.is_title      = "Notas de versão"
    lnv_mb.is_message    = ls_notes
    lnv_mb.il_max_width  = 480
    lnv_mb.il_max_height = 320

    lnv_mb.of_add_button(/*texto*/ "Fechar", /*predefinido*/ true, /*cancelamento*/ true)
    lnv_mb.of_show(/*hwnd*/ Handle(this))

### Reutilizar uma instância #

    // Uma instancia de janela, varios dialogos: of_reset entre cada chamada
    inv_mb.of_reset()      // limpa as propriedades E os botoes anteriores

    inv_mb.is_title   = "Segundo diálogo"
    inv_mb.is_message = "Cada of_reset recomeça a partir de uma caixa vazia."
    inv_mb.of_add_button(/*texto*/ "OK", /*predefinido*/ true, /*cancelamento*/ false)
    inv_mb.of_show(/*hwnd*/ Handle(this))

## Boas práticas #

- Chamar sempre `of_reset()` antes de reconfigurar uma instância reutilizada: sem isso, os botões do diálogo anterior somam-se aos novos.
- Marque sistematicamente um botão predefinido e um botão de cancelamento: o utilizador que trabalha com o teclado espera Enter e Esc.
- Teste o valor de retorno `0`: significa que a caixa foi fechada sem escolha (cruz ou Esc). Trate-o como o cancelamento.
- Passe `Handle(this)` (ou `Handle(parent)`) como janela chamadora: a caixa centra-se sobre ela e a modalidade aplica-se à janela correta.
- Reserve o vermelho e `ICON_ERROR` para os erros verdadeiros; uma confirmação banal merece `ICON_QUESTION`.
- Para uma informação que não exige qualquer resposta, é preferível uma notificação não bloqueante: ver toaster.

← Referência dos componentes · Índice do guia