PBToolboxAI v5 ← Site

form — u_pbt_form #

← Referência dos componentes · Índice do guia

form é um ecrã de introdução de dados inteiro em um só controlo: campos tipados — texto, número, lista, botões de opção, data, hora, cor, caixa de verificação, palavra-passe, e-mail, texto longo, imagem, etiquetas, estrelas — dispostos em colunas e em secções que se recolhem, cada um com o seu rótulo que sobe para a margem. As regras de cada campo (obrigatório, limites, padrão, máscara…) e os seus erros de negócio verificam-se em conjunto; of_is_dirty diz o que mudou desde o carregamento, of_load_row / of_save_row leem e escrevem uma linha de DataWindow. O seu próprio botão OK chama of_validate.

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


Em resumo #

Userobjectu_pbt_form
Classes de itensn_pbt_form_section (secção) → n_pbt_form_field (campo)
Serve paraSubstituir um ecrã de introdução feito de dezenas de controlos colocados à mão por um formulário com tema que se dispõe sozinho e verifica o que se escreve: ficha de cliente, encomenda, definições, um passo de um assistente
ValoresSempre texto, um a um (of_field(endereço).is_value); todos de uma vez e tipados com of_values; uma linha de DataWindow com of_load_row / of_save_row
Opções opt-inib_veto_changes

Início rápido #

// Two columns ; a name at the top, then a section
uo_form.ii_columns = 2
uo_form.of_add_field(/*keys*/ "name", /*label*/ "Name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "name").ib_required = true
uo_form.of_add_section(/*key*/ "order", /*title*/ "Order")
uo_form.of_add_field(/*keys*/ "order/qty", /*label*/ "Quantity", /*type*/ u_pbt_form.TYPE_NUMBER, /*value*/ "1")
uo_form.of_add_field(/*keys*/ "order/due", /*label*/ "Due on", /*type*/ u_pbt_form.TYPE_DATE, /*value*/ "")
// event clicked of cb_ok
// Local variables
n_pbt_json lnv_json

// Every error shown at once, the keyboard on the first
if uo_form.of_validate() > 0 then return

// Valid : read the values, typed, along the same addresses
lnv_json.of_load(/*json*/ uo_form.of_values())
of_save_order(lnv_json.of_get_string(/*path*/ "name"), lnv_json.of_get_number(/*path*/ "order/qty"))

Um endereço por campo #

Um campo designa-se pelo seu endereço: a sua chave sozinha no primeiro nível ("name"), a secção e depois o campo unidos por / dentro de uma secção ("order/qty") — um nível, nunca mais. Uma secção designa-se pela sua chave sozinha. No primeiro nível, uma chave nomeia uma única coisa: uma secção e um campo de cima não a podem partilhar. Os eventos levam o mesmo endereço, o que escreveu; a chave de um campo (o seu último nível) é também o nome da coluna que of_load_row e of_save_row leem.

// A section by its key, a field by its address
uo_form.of_section(/*key*/ "order").ib_collapsed = true
uo_form.of_field(/*keys*/ "order/qty").is_value = "3"

Os tipos de campo #

O tipo escolhe-se uma vez, em of_add_field, e dá o controlo. O valor, esse, é sempre texto — dado, lido, entregue pelos eventos — escrito da mesma forma qualquer que seja a língua do posto. Uma lista, uma data e uma cor abrem-se nas janelas nativas partilhadas por toda a biblioteca, com as cores do tema.

ConstanteControloO valor, em texto
TYPE_STRINGCaixa de texto; uma máscara (is_mask, sintaxe de um EditMask) mostra os seus literais durante a escrita; um botão «…» (ib_ellipsis) abre a sua pesquisaO texto tal como está; mascarado, sem os seus literais (5551234567)
TYPE_TEXTAREATexto em várias linhas; Enter muda de linhaO texto, com as quebras de linha
TYPE_NUMBERCaixa de texto que lê um número na língua de apresentação: o seu separador decimal ou um ponto, o seu agrupamento dos milhares bem formado (1,000 vale mil em inglês, 1.500 mil e quinhentos em alemão, 1 234,5 em francês). Uma entrada ambígua (1,5 em inglês, 1 2) ou que não seja um número fica no ecrã com a mensagem Not a number traduzida, e o valor em vigor não se mexe; Cima / Baixo aumentam-no ou diminuem-no do seu passo (id_step)Com ponto: "12.5"; "" = vazio. Mantido algarismo a algarismo; 12.50 reescrito por 12.5 não é uma alteração
TYPE_BOOLEANUm interruptor (por omissão) ou uma caixa de verificação (is_boolean_style), com o rótulo ao lado"true" · "false"
TYPE_ENUMBotão que abre a lista partilhada; as suas opções acrescentam-se uma a uma (of_add_option)O valor da opção escolhida, nunca o seu texto; um valor que nenhuma opção oferece é mantido e mostrado tal como está, como um DataWindow sem tabela de códigos
TYPE_RADIOUm botão de opção por opção, lado a lado; as setas passam de um para o outroO valor da opção escolhida
TYPE_DATEBotão que abre o calendário partilhado; a data aparece no formato da língua de apresentação"yyyy-mm-dd"
TYPE_TIMECaixa de texto: 9:5 passa a 09:05; o que não é uma hora de 24 h fica no ecrã com a sua mensagem"hh:mm"
TYPE_COLORBotão com a amostra da cor, que abre o seletor partilhadoO long RGB escrito em texto: String(RGB(255, 0, 0)) = "255"
TYPE_PASSWORDCaixa de texto mascaradaO texto tal como está
TYPE_EMAILCaixa de texto que verifica a forma de um endereçoO texto tal como está
TYPE_IMAGEUma imagem, não uma entrada: nunca validada, nunca em of_values; com ii_rowspan cobre várias linhas (a fotografia de uma ficha)A sua origem: um ficheiro, ou mono: / tint: seguido de um caminho (com as cores do tema); um endereço http:// é recusado
TYPE_TAGSEtiquetas em pastilhas numa caixa: escreve-se uma palavra e depois Enter, uma vírgula ou Tab; Backspace na entrada vazia retira a última, cada pastilha tem a sua cruz, Esquerda / Direita percorrem-nas. As opções do campo (of_add_option) são sugestões filtradas durante a escrita; ib_options_only torna-as as únicas escolhas, ii_max_tags limita o seu númeroAs etiquetas unidas por uma vírgula e um espaço: "vip, b2b" (o valor da opção para uma sugestão escolhida). A vírgula é o separador: nunca dentro de uma etiqueta; escrita pelo código separa, os espaços à volta desaparecem, a mesma etiqueta duas vezes (sem distinguir maiúsculas) fica uma vez
TYPE_RATINGEstrelas para clicar, ii_star_count (5 por omissão), meias estrelas com ib_half_stars. Passar o rato pré-visualiza sem mover nada; um clique no valor atual apaga-o. No teclado: setas, Home / End, um algarismo, 0 ou Delete. Uma estrela cheia usa o destaque do componenteO número de estrelas: "4", "3.5"; "" = sem classificação (0 também). Escrito pelo código, arredondado ao passo e mantido dentro das estrelas; um texto ou um negativo é recusado

A validação #

Cada campo leva as suas regras: ib_required (uma caixa obrigatória tem de estar assinalada), is_min / is_max (um número, uma data, uma hora), ii_max_length, is_pattern (uma expressão regular que o valor inteiro deve seguir), is_mask (uma máscara preenchida), is_match (igual a outro campo), e a forma de um e-mail, de um número ou de uma hora. A sua aplicação acrescenta os seus erros de negócio (is_error: já existe), que ficam até o utilizador alterar o campo. Nada aparece a vermelho enquanto o utilizador não tiver saído de um campo: um formulário novo não está a vermelho. of_is_valid e of_invalid_keys respondem sem mostrar nada; of_validate mostra tudo de uma vez e põe o teclado no primeiro campo com erro. Um campo oculto, desativado ou só de leitura não é julgado pelas suas regras: o utilizador não o poderia corrigir.

// A customer code : two capital letters, then four digits
uo_form.of_field(/*keys*/ "code").is_pattern = "[A-Z]{2}[0-9]{4}"
uo_form.of_field(/*keys*/ "code").is_pattern_message = "Two capital letters, then four digits"

// A rule only your database knows
if of_email_taken(uo_form.of_field(/*keys*/ "email").is_value) then
    uo_form.of_field(/*keys*/ "email").is_error = "Already used by another customer"
end if

Propriedades #

PropriedadeTipoPredefiniçãoFunção
ii_columnsinteger1Número de colunas, de 1 a 12 (um valor fora dos limites é trazido para dentro). Cada secção acompanha. Um campo abrange mais com ii_colspan, começa numa coluna dada com ii_col, cobre várias linhas com ii_rowspan; os outros campos preenchem as células livres
ib_readonlybooleanfalseO formulário inteiro só de leitura: cada valor lê-se, nenhum se altera — uma ficha que se consulta. O seu código pode continuar a escrever os valores
ib_veto_changesbooleanfalseOpt-in: perguntar antes de escrever um valor do utilizador (levanta ue_value_changing, que pode recusar: o campo volta a mostrar o valor anterior). Um valor escrito pelo seu código nunca pergunta
is_theme_stylestring""Estilo visual do componente (constantes THEME_STYLE_*); vazio = o da aplicação, seguido a cada mudança
is_theme_modestring""Variante clara ou escura (constantes THEME_MODE_*); vazio = a da aplicação, seguida a cada mudança
il_theme_accentlong-1Cor de destaque deste componente (-1 = destaque da aplicação, ou o do tema)
is_tooltipstring""Tooltip simples apresentado ao passar sobre o componente
is_super_tooltip_titlestring""Título do tooltip enriquecido (prevalece sobre is_tooltip)
is_super_tooltip_textstring""Texto do tooltip enriquecido (aceita marcação enriquecida)
is_super_tooltip_imagestring""Imagem do tooltip enriquecido

Propriedades de uma secção — n_pbt_form_section #

PropriedadeTipoPredefiniçãoFunção
is_titlestring""Título do cabeçalho. Aceita o texto formatado com etiquetas. Vazio, o cabeçalho mostra a chave
ib_collapsedbooleanfalsetrue recolhe a secção: o seu cabeçalho fica, os seus campos escondem-se — mantêm os seus valores e continuam julgados. Segue-se ue_section_toggled, como num clique no cabeçalho. Lida em direto
ib_visiblebooleantruefalse retira a secção, e todos os seus campos, do formulário; mantêm os seus valores (of_values continua a devolvê-los) e não são julgados
is_tooltipstring""Tooltip simples apresentado ao passar sobre o item
is_super_tooltip_titlestring""Título do tooltip enriquecido do item (prevalece sobre is_tooltip)
is_super_tooltip_textstring""Texto do tooltip enriquecido do item (aceita marcação enriquecida)
is_super_tooltip_imagestring""Imagem do tooltip enriquecido do item
il_accentlong-1Destaque do cabeçalho da secção: o traço sob o seu título usa-o (-1 = o do componente). Os seus campos mantêm o seu
il_back_colorlong-1Fundo do cabeçalho da secção, em RGB(r,g,b) (-1 = o que o tema dá)
il_text_colorlong-1Cor do texto do cabeçalho da secção (-1 = o que o tema dá)
il_back_color_hoverlong-1Fundo do cabeçalho da secção sob o ponteiro (-1 = o que o tema dá)
il_text_color_hoverlong-1Cor do texto do cabeçalho da secção sob o ponteiro (-1 = o que o tema dá)

Propriedades de um campo — n_pbt_form_field #

PropriedadeTipoPredefiniçãoFunção
is_valuestring""O valor, em texto (ver os tipos). Escrevê-lo não levanta nada, como SetItem; lê-lo dá o valor atual, seja quem for que o escreveu — o que está a ser escrito conta. Um valor que o tipo não pode conter (uma data que não existe, um texto num número) é recusado: o anterior fica e of_get_last_error diz porquê
is_labelstring""O rótulo, no campo: sobe para a margem quando o campo tem um valor ou o teclado. Aceita o texto formatado com etiquetas. Uma estrela segue o rótulo de um campo obrigatório. Vazio, a chave
is_placeholderstring""Uma indicação num campo de texto vazio enquanto tem o teclado
is_helpstring""Uma linha de ajuda sob o campo (texto formatado com etiquetas); esconde-se enquanto um erro ocupa o seu lugar
is_errorstring""Um erro de negócio da sua aplicação (já existe): mostrado de imediato, o formulário inválido, até o utilizador alterar o campo ou of_clear_errors; "" apaga-o. Lido, dá a mensagem que o campo mostra — ou mostrará quando o utilizador sair dele: o erro de negócio, senão o das suas regras, "" se for válido. Num campo que o utilizador não pode alcançar (oculto, desativado) é mantido e relê-se, mas não conta: o formulário continua válido até o campo voltar
is_minstring""O menor valor aceite para um número (com ponto), uma data (yyyy-mm-dd) ou uma hora (hh:mm); a mensagem diz Minimum e o limite. Um limite que o tipo não lê é ignorado; "" = nenhum — para um número, o extremo inferior da SpinRange da sua coluna de DataWindow (of_load_row). Lido, dá o limite em vigor
is_maxstring""O maior valor aceite, lido como is_min; a mensagem diz Maximum e o limite
is_patternstring""Uma expressão regular (sintaxe JavaScript) que o valor inteiro deve seguir: [A-Z]{2}[0-9]{4} aceita AB1234, não xAB1234. Um valor vazio é deixado a ib_required
is_pattern_messagestring""A mensagem quando is_pattern falha; vazio: Invalid format, traduzida
is_maskstring""Uma máscara de introdução. Num TYPE_STRING, a sintaxe de um EditMask do PowerBuilder: # um algarismo, ! qualquer carácter em maiúscula, ^ qualquer carácter em minúscula, a uma letra ou um algarismo, X qualquer carácter, o resto escrito para o utilizador enquanto escreve ((###) ###-####); o cursor fica depois do que foi escrito. O valor só mantém o que foi escrito nas posições, como um EditMask (5551234567, pronto para uma coluna de algarismos); um valor do código é o valor em bruto, sem os seus literais (312345678 sob +33 # ## ## ## ##), os literais iniciais escrevem-se assim que o campo recebe o teclado, um valor que não preenche todas as posições é Incomplete, e pôr uma máscara depois de um valor não muda nada do que o utilizador fez. Depois de of_load_row, uma máscara vazia usa o EditMask da coluna. Num TYPE_NUMBER: uma máscara numérica na sintaxe do PowerBuilder (EditMask, formato DataWindow): # um algarismo opcional, 0 um algarismo obrigatório, , o agrupamento, . o separador decimal, % o número mostrado vezes 100, literais ($, um texto entre aspas, \x) e secções positivo;negativo ("$#,##0;($#,##0)"). A vírgula e o ponto designam os separadores da língua de apresentação. Durante a escrita, o agrupamento aparece à medida que chegam os algarismos, as casas decimais ficam limitadas à máscara, as letras são recusadas, o cursor mantém o seu lugar entre os algarismos e um número colado é lido na língua de apresentação; ao sair do campo a máscara completa (12 passa a 12,00). O valor mantém o número tal como o código o escreve ("1234.5"), sem agrupamento nem símbolo. Um limite inferior (is_min) de 0 ou mais recusa o sinal menos; os limites aplicam-se ao sair do campo, e a sua mensagem mostra-os através da máscara; vazio num TYPE_NUMBER (por omissão): o campo escreve-se segundo o seu is_format sem os seus literais ($#,##0.00 escreve-se #,##0.00, #,##0 "px" escreve-se #,##0; um % fica, é uma escala)
is_formatstring""Um TYPE_NUMBER: o seu formato de apresentação, como o número se mostra enquanto o campo não tem o teclado — a mesma sintaxe de is_mask, com os seus literais: #,##0 "px" mostra 575 px, $#,##0.00;($#,##0.00) um preço, 0.0% uma taxa (0,125 mostra 12,5%). Quando o campo recebe o teclado, o seu texto passa a ser o de is_mask (575), o cursor mantendo o seu lugar entre os algarismos; ao sair volta o texto de apresentação. A troca nunca altera o valor e não levanta nada: ue_value_changed só relata o que o utilizador escreveu, o número nu. Vazio: o campo mostra o seu is_mask
is_boolean_stylestring"switch"Um TYPE_BOOLEAN: como é desenhado. BOOLEAN_SWITCH (por omissão): um interruptor, uma pista e um círculo que desliza para o fim, na cor de destaque do componente, quando está ligado — uma definição ligado / desligado. BOOLEAN_CHECKBOX: a caixa de verificação clássica — uma aceitação, uma escolha entre opções. Ambos respondem a Espaço e a um clique no rótulo, dão o mesmo valor e os mesmos eventos; desativados ou só de leitura continuam legíveis. O círculo desliza num quarto de segundo, nada quando o Windows pede menos animações; numa língua escrita da direita para a esquerda desliza para a esquerda
ii_max_tagsinteger0Um TYPE_TAGS: o número máximo de etiquetas (0 = sem limite). Uma a mais escrita pelo utilizador é recusada: fica na entrada com a mensagem At most N; uma lista mais longa escrita pelo código é mantida, e o campo fica inválido (of_is_valid, is_error) — mostrado depois de o campo ser tocado ou após of_validate, nunca logo
ib_options_onlybooleanfalseUm TYPE_TAGS: true limita as suas etiquetas às opções do campo (of_add_option) — um texto que não nomeia nenhuma (pelo seu texto ou valor, sem maiúsculas nem acentos) é recusado com Not in the list. false: qualquer texto é uma etiqueta, as opções são só sugestões
ii_star_countinteger5Um TYPE_RATING: o número de estrelas, de 1 a 10 (um número fora é trazido para dentro). O valor atual fica dentro delas, sem evento: definir o número antes de um valor acima de cinco
ib_half_starsbooleanfalseUm TYPE_RATING: true permite meias estrelas — a primeira metade da estrela sob o ponteiro (no sentido de leitura), Esquerda / Direita de meia estrela — e o valor escreve-se "3.5". Desligado, o valor atual é arredondado a uma estrela inteira, sem evento: ligá-lo antes de um meio valor
is_matchstring""O endereço de outro campo ao qual este deve ser igual — repetir uma palavra-passe, um e-mail. A mensagem acompanha cada alteração de um ou de outro
is_prefixstring""Um texto curto no campo, antes do valor (um símbolo de moeda); não faz parte do valor
is_suffixstring""Um texto curto no campo, depois do valor (uma unidade); não faz parte do valor
ii_max_lengthinteger0O texto mais longo aceite (0 = sem limite) por um TYPE_STRING, TYPE_TEXTAREA, TYPE_PASSWORD ou TYPE_EMAIL — um número ou uma hora não tem comprimento, ignorado; 0 usa o Limit da sua coluna de DataWindow (of_load_row), lido dá o comprimento em vigor: a escrita para aí, um contador aparece sob um campo de texto; um valor mais longo escrito pelo código é Too long. Num TYPE_TAGS: a etiqueta mais longa — uma colagem de várias etiquetas nunca é cortada, cada uma é julgada
ii_colspaninteger1Quantas colunas o campo abrange (no máximo ii_columns); -1 = toda a largura
ii_rowspaninteger1Quantas linhas o campo cobre — uma imagem ao lado de vários campos; os seguintes preenchem as células livres ao lado
ii_colinteger0A coluna onde o campo começa, a partir de 1; 0 = onde o fluxo o coloca. A tecla Tab segue a ordem do ecrã — primeiro os campos de cima, depois cada secção —, qualquer que seja a coluna
ib_requiredbooleanfalseO campo tem de ser preenchido — uma caixa tem de estar assinalada (uma caixa Aceito), um campo de etiquetas conter uma, uma classificação ter uma estrela. Uma estrela segue o seu rótulo; o erro Required aparece quando o utilizador sai do campo ou em of_validate. Uma coluna cujo estilo de edição diz Required torna-o obrigatório também (of_load_row); lido, dá o estado em vigor
ib_readonlybooleanfalseMostra o valor sem o deixar mudar: um texto ainda pode ser selecionado e copiado; uma lista, uma data, uma cor, um interruptor ou botões de opção mantêm o teclado (Tab alcança-os, um leitor de ecrã diz só de leitura) mas não se abrem nem mudam. Não é julgado pelas suas regras; o seu código pode continuar a escrever is_value
ib_enabledbooleantruefalse desativa o campo: sem teclado (sai da ordem de tabulação), sem clique, não é julgado pelas suas regras
ib_visiblebooleantruefalse retira o campo do formulário; mantém o seu endereço e o seu valor (of_values continua a devolvê-lo) e não é julgado
is_columnstring""A coluna do DataWindow que of_load_row e of_save_row leem e escrevem para este campo; "" (por omissão) = a sua chave, o último nível do seu endereço. Duas secções podem assim ter a mesma chave (billing/town, shipping/town) ligada a duas colunas, e um campo manter uma chave legível para uma coluna chamada cust_nm
id_stepdouble0Um TYPE_NUMBER: o que Cima / Baixo (e os seus botões, ib_spin) acrescentam ou retiram, mantido entre is_min e is_max; 0 (por omissão) = o SpinIncr da sua coluna de DataWindow (of_load_row), senão 1. Um passo é um gesto do utilizador: ue_value_changed é levantado (e ue_value_changing colocado antes com ib_veto_changes). Um campo vazio parte de is_min, senão de 0; um passo negativo é recusado
ib_ellipsisbooleanfalseUm campo de texto (TYPE_STRING, TYPE_NUMBER, TYPE_EMAIL…): true mostra um botão … no seu fim — a sua pesquisa, um cliente, um artigo. Um clique nele, ou Ctrl+Enter no campo, levanta ue_ellipsis_clicked; fica fora da ordem de Tab. Funciona também num campo só de leitura (um valor escolhido só pela pesquisa), nunca num desativado
ib_spinbooleanfalseUm TYPE_NUMBER: true mostra dois pequenos botões no seu fim, cima e baixo, que acrescentam ou retiram id_step entre is_min e is_max — um gesto do utilizador (ue_value_changed). A roda do rato também o faz enquanto o campo tem o teclado; os botões ficam fora da ordem de Tab (Cima / Baixo no campo fazem o mesmo) e escondem-se num campo só de leitura. Uma coluna cujo EditMask diz Spin dá-os por of_load_row, com o seu SpinIncr como passo e a sua SpinRange como limites. Ignorado pelos outros tipos; lido, dá o estado em vigor
of_type ( ) → string——O tipo dado a of_add_field (uma constante TYPE_*). Só de leitura: um tipo escolhe-se uma vez
of_is_dirty ( ) → boolean——TRUE quando este campo difere da sua referência (ver of_is_dirty do formulário)
of_is_valid ( ) → boolean——TRUE quando este campo não tem nenhum erro; is_error diz qual
is_tooltipstring""Tooltip simples apresentado ao passar sobre o item
is_super_tooltip_titlestring""Título do tooltip enriquecido do item (prevalece sobre is_tooltip)
is_super_tooltip_textstring""Texto do tooltip enriquecido do item (aceita marcação enriquecida)
is_super_tooltip_imagestring""Imagem do tooltip enriquecido do item
il_accentlong-1Destaque do campo: a sua margem usa-o quando tem o teclado, e o seu rótulo depois de subir (-1 = o do componente)
il_back_colorlong-1Fundo do campo, em RGB(r,g,b) (-1 = o que o tema dá)
il_text_colorlong-1Cor do texto do campo (-1 = o que o tema dá)
il_back_color_hoverlong-1Fundo do campo sob o ponteiro (-1 = o que o tema dá)
il_text_color_hoverlong-1Cor do texto do campo sob o ponteiro (-1 = o que o tema dá)

Métodos #

No componente #

MétodoFunção
of_add_section (string as_key, string as_title) → longAcrescenta uma secção no fim: um cabeçalho que se recolhe, sublinhado com o destaque, sob o qual se acrescentam depois os campos "chave/nome". Um título vazio mostra a chave. Devolve 0 uma vez acrescentada, -5 para uma chave vazia, que contenha / ou `, ou já ocupada por uma secção ou um campo de cima, -2` se o componente não estiver criado
of_add_field (string as_keys, string as_label, string as_type, string as_value) → longAcrescenta um campo no seu endereço, no fim do que o contém: a sua secção ou o topo do formulário. as_type é uma constante TYPE_*, as_value o seu valor em texto (a origem de uma imagem). Devolve 0 uma vez acrescentado, -5 para um endereço já ocupado (um campo, ou uma secção no primeiro nível), um nível vazio, mais de dois níveis, uma secção nunca acrescentada, uma chave que contenha `, um tipo desconhecido ou um valor que o tipo não pode conter (of_get_last_error diz porquê), -2` se o componente não estiver criado
of_add_option (string as_keys, string as_value, string as_text) → longAcrescenta uma opção, no fim, a uma lista TYPE_ENUM, a botões TYPE_RADIO ou às sugestões de um TYPE_TAGS: as_value é o que o campo contém (e o que ue_value_changed dá), as_text o que o utilizador lê, como texto simples ("" mostra o valor). Devolve 0 uma vez acrescentada, -5 para um endereço que não seja uma lista, botões de opção nem etiquetas, um valor já oferecido, um valor que contenha ` ou / (of_keys_at junta-o ao endereço do campo) — e para etiquetas um valor vazio ou com uma vírgula —, -2` se o componente não estiver criado
of_remove_option (string as_keys, string as_value) → longRetira uma opção de uma lista, de botões de opção ou de etiquetas, pelo seu valor; o valor do campo fica como está. Devolve 0 uma vez retirada, -5 para um endereço que não seja uma lista, botões de opção nem etiquetas, ou um valor que não oferece, -2 se o componente não estiver criado
of_clear_options (string as_keys) → longRetira todas as opções de uma lista, de botões de opção ou de etiquetas, para carregar outra lista sem perder o campo, o seu handle nem o seu estado; o seu valor fica como está. Devolve 0 uma vez limpa, -5 para um endereço que não seja uma lista, botões de opção nem etiquetas, -2 se o componente não estiver criado
of_remove_field (string as_keys) → longRetira um campo pelo seu endereço, com o seu handle; o resto do formulário mantém o seu estado. Devolve 0 uma vez retirado, -5 para um endereço nunca acrescentado, -2 se o componente não estiver criado
of_remove_section (string as_key) → longRetira uma secção e todos os seus campos, com os seus handles. Devolve 0 uma vez retirada, -5 para uma secção nunca acrescentada, -2 se o componente não estiver criado
of_clear ( ) → longLimpa o formulário: secções, campos e os seus handles. Ao contrário de of_reset, as colunas, a só leitura e a pergunta ficam. Devolve 0 uma vez limpo, -2 se o componente não estiver criado
of_section (string as_key) → n_pbt_form_sectionO handle de uma secção, pela sua chave: título, recolhimento, visibilidade, cores e dica. Criado no primeiro acesso
of_field (string as_keys) → n_pbt_form_fieldO handle de um campo, pelo seu endereço: of_field("order/qty").is_value = "3". Criado no primeiro acesso
of_values ( ) → stringTodos os valores de uma vez, lidos em direto, num objeto JSON: os campos de cima, depois cada secção como um objeto próprio — ocultos incluídos, imagens excluídas; o que o utilizador ainda escreve é validado primeiro, como faz AcceptText: ue_value_changing colocado com ib_veto_changes, depois ue_value_changed levantado — ambos antes da leitura, nunca a meio: o seu OK lê o que está no ecrã. Tipados: um número é um número (escrito algarismo a algarismo, null se vazio), um booleano um booleano, uma cor o seu long RGB, o resto texto. Lê-se com n_pbt_json, pelo mesmo endereço: lnv_json.of_get_number("order/qty")
of_load (string as_json) → longCarrega um registo: um objeto JSON de valores por endereço — os campos de cima, depois um objeto por secção, ou chaves "order/qty" —, a forma que of_values devolve; números e booleanos podem vir tipados — um número com mais de 15 algarismos é lido algarismo a algarismo, um booleano vale true, false, 1 ou 0 (qualquer outro valor é recusado). Os valores escrevem-se em silêncio e passam a ser a referência de of_is_dirty; os erros mostrados e os erros de negócio apagam-se. Um campo que o objeto não nomeia mantém o seu valor. Devolve 0 uma vez carregado, -5 para um texto que não seja um objeto JSON, ou um valor que o seu campo não pode conter (abc para um número) — nada é escrito então, of_get_last_error nomeia os campos —, -2 se o componente não estiver criado
of_load_row (powerobject apo_data, long al_row) → longCarrega uma linha de um DataWindow, de um DataStore ou de um DataWindowChild: cada campo recebe o valor da sua coluna — a que is_column nomeia, senão a sua chave (o último nível do seu endereço) —, tipado — uma data yyyy-mm-dd, uma hora hh:mm, um número com ponto, um booleano lido pelo valor On de uma coluna caixa de verificação (senão 1, Y, true…). O que o DataWindow diz da coluna vem com ela, relido a cada carregamento: um campo sem rótulo mostra o texto de cabeçalho da sua coluna, um campo sem máscara nem formato usa o seu EditMask e o seu Format (um número $#,##0), uma lista ou botões de opção sem opções próprias oferecem a sua tabela de códigos ou as linhas da sua DropDownDataWindow; um campo sem regras próprias torna-se obrigatório quando o estilo de edição diz Required e limitado ao seu Limit, e um número cujo EditMask diz Spin recebe os seus botões (ib_spin), o seu passo (SpinIncr) e os seus limites (SpinRange). A linha seguinte do mesmo DataWindow não redesenha nenhum campo: o que tem o teclado mantém-no. Como em of_load, os valores passam a ser a referência. Devolve 0 uma vez carregada, -5 para um objeto que não seja um DataWindow, um DataStore nem um DataWindowChild, uma linha que não exista, ou um valor que o seu campo não pode conter (nada muda então: nem um valor nem o que o DataWindow diz), -2 se o componente não estiver criado
of_save_row (powerobject apo_data, long al_row) → longEscreve os valores que o utilizador alterou (desde a referência: of_load_row, of_reset_update) numa linha de um DataWindow, de um DataStore ou de um DataWindowChild: cada campo alterado na sua coluna (is_column, senão a sua chave), por SetItem, tipado para a coluna (data, datetime, hora, número, texto; um booleano como valor On / Off de uma coluna caixa de verificação, 1 / 0 numa coluna numérica, true / false numa coluna de texto; um campo vazio escreve um NULL — um texto vazio, um NULL onde a sua coluna diz NilIsNull, uma cadeia vazia senão, como o DataWindow). Um campo que o utilizador não alterou não é escrito: a linha mantém o seu estado, o seu Update só envia o que mudou. Um TYPE_DATE mantém a hora de uma coluna datetime, um TYPE_TIME a sua data. O que o utilizador ainda escreve é validado primeiro, e ue_value_changed levantado, antes de qualquer leitura; o Update continua a ser seu. Devolve 0 uma vez escrita, -5 para um objeto que não seja um DataWindow, um DataStore nem um DataWindowChild, ou uma linha que não exista, -4 quando uma coluna ficou como estava — um SetItem recusado, um campo cujo tipo a coluna não pode conter (um TYPE_STRING numa coluna de data), ou um valor com casas decimais para uma coluna inteira (3.5 estrelas num long: SetItem arredondá-lo-ia): of_get_last_error nomeia a primeira, os outros campos alterados são escritos na mesma —, -2 se o componente não estiver criado
of_is_valid ( ) → booleanTRUE quando nenhum campo mostrado tem um erro: cada campo obrigatório preenchido (uma caixa obrigatória assinalada), cada regra seguida, nenhum erro de negócio. Lido em direto, sem mostrar nada; um erro de negócio só conta num campo que o utilizador pode alcançar (mostrado e ativo)
of_invalid_keys (ref string as_keys[]) → longPreenche as_keys[] com os endereços dos campos com erro, pela ordem do ecrã, sem mostrar nada, e devolve o seu número (0 = o formulário é válido)
of_validate ( ) → longMostra todos os erros de uma vez e põe o teclado no primeiro campo com erro (ue_focus_changed) — o que o seu botão OK chama antes de gravar. O teclado sai do botão para o formulário: a tecla seguinte vai para o campo; o que o utilizador ainda escreve é validado primeiro, e um leitor de ecrã lê as mensagens de imediato. Devolve o número de campos com erro (0 = o formulário é válido, nada se mexe), -2 se o componente não estiver criado
of_clear_errors ( ) → longApaga todos os erros de negócio (is_error escrito pelo seu código); os erros das regras ficam. Devolve 0 uma vez aplicado, -2 se o componente não estiver criado
of_is_dirty ( ) → booleanTRUE quando pelo menos um campo difere da sua referência: o valor dado ao acrescentar, ou o que of_load, of_load_row ou of_reset_update fizeram dele; o que o utilizador ainda escreve é validado primeiro. Um número escrito de outra forma (12.50 por 12.5) é o mesmo valor
of_dirty_keys (ref string as_keys[]) → longPreenche as_keys[] com os endereços dos campos alterados desde a referência, pela ordem do ecrã, e devolve o seu número
of_reset_update ( ) → longOs valores no ecrã passam a ser a referência: of_is_dirty volta a responder FALSE. Chame-o depois de o seu Update ter resultado, como ResetUpdate de um DataWindow. Devolve 0 uma vez aplicado, -2 se o componente não estiver criado
of_revert ( ) → longRepõe cada campo no seu valor de referência, em silêncio, e esconde os erros — o Cancelar do utilizador. Devolve 0 uma vez aplicado, -2 se o componente não estiver criado
of_focus_field (string as_keys) → longPõe o teclado num campo, como um clique: a sua secção recolhida abre-se primeiro (ue_section_toggled), segue-se ue_focus_changed. Devolve 0 uma vez feito, -5 para um endereço nunca acrescentado ou um campo que o utilizador não pode alcançar (oculto, desativado — incluindo o que tinha o teclado —, uma imagem, para lá do limite da demonstração), -2 se o componente não estiver criado
of_current_key ( ) → stringEndereço do campo que tem o teclado — ou o teve por último, enquanto o teclado está noutro sítio da janela: "order/qty", "" se ainda nenhum. Sempre o atual, lido do componente; é também o que ue_focus_changed dá
of_get_last_error ( ) → stringPorque é que a última escrita foi recusada: um valor que o tipo não pode conter (is_value não tem código de retorno; uma imagem http://, um número infinito como 1e400), um is_pattern que o formulário não sabe ler, um valor que of_load recusou, uma coluna que of_save_row deixou. Vazio quando passou; senão o último erro da biblioteca, como em qualquer componente
of_reset ( ) → longLimpa o formulário e depois repõe cada propriedade do componente no seu valor por omissão: uma coluna, nem só leitura nem pergunta. Devolve 0 uma vez aplicado, -2 se o componente não estiver criado

Numa secção e num campo #

Uma secção contém campos; uma lista ou botões de opção contêm as suas opções, designadas pelo seu valor. Os três métodos percorrem-nos.

MétodoFunção
of_count ( ) → longNúmero de campos da secção, ocultos incluídos; número de opções de uma lista, de botões de opção ou de etiquetas (0 para os outros tipos)
of_keys_at (long al_index) → stringEndereço do campo de posição al_index (a partir de 1) — "order/qty", reutilizável tal como está em of_field; numa lista, o endereço seguido do valor da opção. "" fora dos limites
of_has (string as_key) → booleanA secção contém este campo? A lista oferece este valor?

Eventos #

EventoAcionado quando
ue_value_changed (string as_keys, string as_value)O utilizador alterou um valor: uma entrada validada ao sair do campo ou com Enter, uma caixa assinalada, um botão de opção, uma opção, uma data ou uma cor escolhidas (Cima / Baixo percorrem uma lista, Delete limpa uma lista, uma data ou uma cor). as_keys é o endereço do campo, as_value o seu novo valor em texto; já está escrito. Um valor escrito pelo seu código não levanta nada, como SetItem. O que o utilizador ainda escreve quando o seu código lê o formulário (of_values, of_save_row, is_value…) é validado nesse momento, como faz AcceptText: o evento é levantado aí, antes da leitura
ue_value_changing (string as_keys, string as_value) → booleanCancelável, colocado antes de um valor do utilizador ser escrito, e só quando ib_veto_changes = true (desativado por omissão). Devolver FALSE recusa: o campo volta a mostrar o valor anterior, que of_field(as_keys).is_value ainda devolve durante o evento. Devolva TRUE para aceitar. Quando o seu código lê o formulário (of_values, of_validate, is_value…) enquanto o utilizador ainda escreve num campo, a pergunta é colocada de imediato, antes da leitura: a leitura devolve o valor que aceitou
ue_focus_changed (string as_from_keys, string as_keys)O campo que tem o teclado mudou: um clique, a tecla Tab, o seu código (of_focus_field, of_validate — uma ordem também o levanta, como SetColumn), ou o campo saiu: retirado, ocultado, limpo (as_keys vale então ""). O teclado que sai do formulário para outro controlo da janela não levanta nada
ue_section_toggled (string as_key, boolean ab_collapsed)Uma secção recolheu-se (ab_collapsed = TRUE) ou expandiu-se: um clique no seu cabeçalho (Enter ou Espaço quando tem o teclado), o seu ib_collapsed definido pelo seu código, ou of_focus_field sobre um campo de uma secção recolhida
ue_ellipsis_clicked (string as_keys)O botão … de um campo (ib_ellipsis) foi clicado, ou Ctrl+Enter premido no campo: abra a sua pesquisa (um cliente, um artigo) e escreva o que o utilizador escolheu em of_field(as_keys).is_value. O que foi escrito já está validado (ue_value_changing colocado antes com ib_veto_changes, ue_value_changed levantado). Nunca levantado para um campo desativado
ue_ready ( )O componente terminou o carregamento; tudo o que foi enviado antes foi reproduzido
ue_runtime_missing ( )O runtime WebView2 está ausente: o componente permanece vazio
ue_bg_color (long al_color)O componente calculou a cor de fundo do respetivo tema; o userobject já a adotou (backcolor)

Teclado e rato #

GestoEfeito
Tab, Shift+TabPassam de um campo para o outro, pela ordem do ecrã: os campos de cima, depois cada secção, primeiro o seu cabeçalho; um campo desativado é saltado; os botões de opção são uma paragem, as setas escolhem
Enter num campo de uma linhaValida a entrada e depois passa para a janela: o seu botão por omissão (o seu OK) lê um formulário atualizado. Com ib_veto_changes, a página não pergunta nada: a entrada fica pendente, e a leitura do botão por omissão valida-a (ue_value_changing colocado nesse momento) — sem botão por omissão, valida-a a saída do campo
EscNum campo que o utilizador alterou, repõe o seu valor; senão passa para a janela: o seu botão Cancelar
Lista, data, cor: Enter, Espaço, F4, Alt+BaixoAbrem a janela partilhada (lista, calendário, seletor de cor); Enter fica por aí, não passa para o botão por omissão da janela — nem num cabeçalho de secção, que recolhe ou expande
Lista: Cima / BaixoOpção anterior / seguinte, sem abrir a lista
Lista, data, cor: Delete, BackspaceLimpam o valor
Etiquetas: Enter, vírgula, TabAcrescentam o que foi escrito (Tab mantém o teclado no campo); Backspace na entrada vazia retira a última etiqueta; Esquerda / Direita percorrem as etiquetas, Delete retira a assinalada; Baixo abre as sugestões, Esc fecha-as
Estrelas: setas, Home / End, algarismos, DeleteDireita / Cima uma estrela a mais (meia com ib_half_stars), Esquerda / Baixo uma a menos — trocadas numa língua escrita da direita para a esquerda; Home uma estrela, End todas; um algarismo tantas estrelas; 0, Delete ou Backspace apagam a classificação
Número: Cima / BaixoAcrescentam ou retiram o passo do campo (id_step, 1 por omissão), mantido entre is_min e is_max: segue-se ue_value_changed. Com ib_spin, os seus dois botões fazem o mesmo, e a roda enquanto tem o teclado
Ctrl+Enter, clique em …Um campo com ib_ellipsis: valida o que foi escrito e depois levanta ue_ellipsis_clicked — a sua pesquisa
Clique num cabeçalho de secçãoRecolhe ou expande a secção (ue_section_toggled)

Exemplos #

Uma ficha de cliente #

// The whole form in one paint, two columns
uo_form.of_set_redraw(/*on*/ false)
uo_form.ii_columns = 2

// Identity : two required names, an e-mail, a phone with its mask
uo_form.of_add_section(/*key*/ "identity", /*title*/ "Identity")
uo_form.of_add_field(/*keys*/ "identity/first_name", /*label*/ "First name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/first_name").ib_required = true
uo_form.of_add_field(/*keys*/ "identity/last_name", /*label*/ "Last name", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/last_name").ib_required = true
uo_form.of_add_field(/*keys*/ "identity/email", /*label*/ "E-mail", /*type*/ u_pbt_form.TYPE_EMAIL, /*value*/ "")
uo_form.of_add_field(/*keys*/ "identity/phone", /*label*/ "Phone", /*type*/ u_pbt_form.TYPE_STRING, /*value*/ "")
uo_form.of_field(/*keys*/ "identity/phone").is_mask = "(###) ###-####"

// Account : a credit limit with a bound, shown as a price and typed without the
// dollar sign ; a list ; a switch
uo_form.of_add_section(/*key*/ "account", /*title*/ "Account")
uo_form.of_add_field(/*keys*/ "account/credit_limit", /*label*/ "Credit limit", /*type*/ u_pbt_form.TYPE_NUMBER, /*value*/ "2500")
uo_form.of_field(/*keys*/ "account/credit_limit").is_format = "$#,##0.00"
uo_form.of_field(/*keys*/ "account/credit_limit").is_max = "50000"
uo_form.of_add_field(/*keys*/ "account/country", /*label*/ "Country", /*type*/ u_pbt_form.TYPE_ENUM, /*value*/ "gb")
uo_form.of_add_option(/*keys*/ "account/country", /*value*/ "gb", /*text*/ "United Kingdom")
uo_form.of_add_option(/*keys*/ "account/country", /*value*/ "fr", /*text*/ "France")
uo_form.of_add_field(/*keys*/ "account/vip", /*label*/ "VIP customer", /*type*/ u_pbt_form.TYPE_BOOLEAN, /*value*/ "false")

// Shown at once, the keyboard on the first field
uo_form.of_set_redraw(/*on*/ true)
uo_form.of_focus_field(/*keys*/ "identity/first_name")

Editar uma linha de DataWindow #

A chave de cada campo é o nome da sua coluna: o formulário lê a linha, o utilizador altera-a, o formulário escreve-a.

// The current row of dw_customers fills the form ; nothing is dirty yet
uo_form.of_load_row(/*data*/ dw_customers, /*row*/ dw_customers.GetRow())
// event clicked of cb_save
if uo_form.of_validate() > 0 then return

// Write the values back into the row, then save it
if uo_form.of_save_row(/*data*/ dw_customers, /*row*/ dw_customers.GetRow()) < 0 then
    MessageBox("Save", uo_form.of_get_last_error())
    return
end if

// Saved : what is on screen is the new reference
if dw_customers.Update() = 1 then
    COMMIT USING SQLCA;
    uo_form.of_reset_update()
end if

Etiquetas e estrelas #

Uma avaliação de um produto: uma nota em cinco com meias estrelas, e etiquetas livres com sugestões. Os dois valores continuam a ser texto, que of_save_row escreve numa coluna numérica e numa coluna de texto.

// Local variables
string ls_score, ls_tags

// The score : five stars, half stars set BEFORE a half value
uo_form.of_add_field(/*keys*/ "score", /*label*/ "Overall", /*type*/ u_pbt_form.TYPE_RATING, /*value*/ "")
uo_form.of_field(/*keys*/ "score").ib_half_stars = true
uo_form.of_field(/*keys*/ "score").is_value = "3.5"

// Tags : free text, the options are suggestions, five at most
uo_form.of_add_field(/*keys*/ "tags", /*label*/ "Tags", /*type*/ u_pbt_form.TYPE_TAGS, /*value*/ "office, led")
uo_form.of_add_option(/*keys*/ "tags", /*value*/ "eco", /*text*/ "Eco-friendly")
uo_form.of_add_option(/*keys*/ "tags", /*value*/ "usb", /*text*/ "USB powered")
uo_form.of_field(/*keys*/ "tags").ii_max_tags = 5

// Read back : "3.5" and "office, led"
ls_score = uo_form.of_field(/*keys*/ "score").is_value
ls_tags = uo_form.of_field(/*keys*/ "tags").is_value

Avisar antes de perder alterações #

// event closequery of the window
if not uo_form.of_is_dirty() then return 0

// Changes since the load : ask, and put them back if the user gives up
if MessageBox("Customer", "Discard your changes ?", Question!, YesNo!) = 2 then return 1
uo_form.of_revert()
return 0

Boas práticas #

Herdado da base comum #

Estes membros existem em todos os componentes visuais — não são próprios deste. São detalhados uma só vez, nos capítulos transversais; esta tabela apenas diz onde os ler.

MembrosFunçãoDetalhado em
of_count · of_keys_at · of_hasPercorrer o que o componente contém3.2 Os items
of_resetRepor o componente a zero3.6 Repor um componente a zero: of_reset()
of_register_shortcut · of_clear_shortcutsAtalhos de teclado do componente3.5 Os atalhos de teclado
of_is_created · of_is_ready · of_get_last_errorSe nasceu, se está pronto, o que falhou3.7 Diagnóstico
of_save_as_png · of_save_as_jpgExportar a renderização como imagem3.8 Exportar a representação como imagem
of_set_redrawAgrupar as alterações num único repinte3.10 Boas práticas
of_preload_iconsÍcones mostrados sem atrasoApresentação instantânea: of_icon
of_set_translationTraduzir uma legenda do componente5.2 Adaptar uma etiqueta: of_set_translation
of_focus_webviewDar o foco ao componente6.4 Teclado e focus
of_print · of_print_to_pdfImprimir, ou escrever um PDF6.9 Imprimir
of_set_property · of_get_property · of_component_nameControlar uma propriedade pelo nome3.1 O motor de propriedades
is_accessible_name · is_accessible_descriptionO nome e a descrição que um leitor de ecrã diz3.4 Propriedades e eventos opcionais

Duas ajudas não são herdadas: of_icon e of_escape_markup vivem em n_pbt_utils. Declare um — n_pbt_utils lnv_utils, nada a criar — e chame-as nele.

← Referência dos componentes · Índice do guia