3. Base comum u_pbt_base #
← Primeiros passos · Índice · Temas →
Todos os componentes visuais herdam de u_pbt_base, que fornece o ciclo de vida, o motor de propriedades, o transporte para o componente web e a gestão de erros. As propriedades propriamente ditas — tema e tooltips incluídos — são publicadas por cada componente: a página do componente apresenta a lista completa. u_pbt_base nunca é utilizado diretamente — coloca-se sempre um componente concreto — mas tudo o que se segue está disponível em qualquer lado.
3.1 O motor de propriedades #
Atribuir #
Qualquer valor controlável é uma variável de instância pública, atribuída diretamente:
uo_progress.id_value = 42.5
uo_progress.is_label = "Importação em curso…"
uo_progress.ib_animated = true
O prefixo húngaro indica o tipo: is_ string, ib_ boolean, ii_ integer, il_ long (muitas vezes uma cor RGB()), id_ double.
Não existe nenhum of_set_xxx escalar: uma propriedade define-se por atribuição. Continuam a ser métodos as adições, remoções e ações (of_add_*, of_remove_*, of_select_*, of_reset, of_set_layout…).
Reler #
A leitura devolve o último valor definido (cache do lado do PowerBuilder):
if uo_progress.id_value >= 100 then …
Um componente web não pode ser interrogado de forma síncrona: essa cache é, portanto, atualizada pelos eventos. Sempre que o componente move uma propriedade por si próprio — o utilizador segue uma ligação, amplia com a roda, recolhe o friso, escreve texto — o evento que o avisa atualiza a propriedade de passagem. A releitura devolve então o estado real, e o novo valor já está colocado quando o código do evento é executado.
O mesmo vale para os itens: após um clique do utilizador, of_item(...) relê o que está no ecrã — a entrada selecionada, a secção recolhida, o botão marcado.
Uma propriedade que nenhum evento acompanha permanece no último valor que definiu.
Agrupar as modificações #
Uma rajada de atribuições provoca outros tantos desenhos. of_set_redraw funde-os num único:
uo_grid.of_set_redraw(false)
… vinte atribuicoes e of_add_* …
uo_grid.of_set_redraw(true) // UM unico repaint
Devem chamar-se sempre os dois (o true final não é opcional).
3.2 Os items #
Um componente com conteúdo (separadores, botões, painéis, mosaicos, secções…) expõe os seus elementos através de handles tipados, obtidos a partir do componente ou do respetivo elemento pai.
Adicionar #
A adição devolve o handle do elemento criado:
n_pbt_tab_page lnv_page
uo_tab.of_add_page("clients", "Clientes", uo_page_clients)
lnv_page = uo_tab.of_item("clients")
lnv_page.is_icon = "img\clients.png"
Localizar e modificar #
of_item(id) — ou a fábrica do nível em causa — devolve o handle de um elemento existente; as respetivas propriedades definem-se como as de um componente:
uo_toolbar.of_bar("main").of_item("save").ib_enabled = false
uo_tab.of_item("clients").is_title = "Clientes (128)"
Hierarquias: um identificador só é único dentro do respetivo elemento pai #
Um componente com vários níveis não expõe qualquer atalho para a folha: o caminho é obrigatório, o que garante que nenhum identificador seja ambíguo.
// Friso : separador > grupo > controlo > entrada de menu
uo_ribbon.of_tab("home").of_group("clipboard").of_item("paste").ib_enabled = false
Os eventos transportam igualmente o caminho completo:
// evento ue_clicked de uo_toolbar : (string as_bar, string as_id)
choose case as_bar + "/" + as_id
case "main/save" ; of_enregistrer()
end choose
Eventos de item #
Não existem eventos de item genéricos no antecessor: um identificador de folha isolado seria ambíguo assim que os items são aninhados (uma toolbar tem várias barras, uma tilesbox vários grupos…). Cada componente declara portanto os seus eventos de item, com o caminho completo: ue_item_selected (as_section, as_id) para a listbar, ue_tile_clicked (as_group, as_id) para a tilesbox, ue_clicked (as_bar, as_id) para a toolbar…
Consulte a página do componente: é aí que consta a lista exata.
3.3 Eventos comuns a todos os componentes #
| Evento | Acionado quando |
|---|---|
ue_ready ( ) | O componente terminou o carregamento; tudo o que foi enviado antes foi reproduzido |
ue_runtime_missing ( ) | O runtime WebView2 está ausente — ver Instalação |
ue_bg_color (long al_color) | O componente calculou a cor de fundo do respetivo tema; o userobject já adotou essa cor (backcolor), cabendo ao programador harmonizar a window se necessário |
Os comandos enviados antes de
ue_readynão se perdem: são colocados em fila e reproduzidos pela mesma ordem. É, portanto, possível configurar tudo logo noconstructorou noopen.
// evento ue_bg_color : harmonizar a window com o fundo do componente
parent.backcolor = al_color
3.4 Propriedades e eventos opcionais (opt-in) #
Determinadas funcionalidades não estão ativas por predefinição: só são publicadas pelos componentes onde fazem sentido e têm de ser pedidas.
Altura automática — ib_auto_height #
O componente mede a sua altura ideal e redimensiona o userobject; o evento ue_auto_height(al_height) permite reposicionar os controlos vizinhos.
uo_entete.ib_auto_height = true
// evento ue_auto_height de uo_entete
il_hauteur_entete = al_height
of_relayout() // reposiciona o conteudo por baixo
Publicada por: picture e statictext.
As faixas não publicam esta propriedade — a sua altura é intrínseca. O ribbon e a toolbar não deslocam verticalmente: uma altura fixa só pode produzir espaço vazio por baixo da faixa ou conteúdo truncado (faixa de opções recolhida, barra de ferramentas distribuída por duas filas…). Ajustam-se, portanto, sempre, sem nada para ativar, e continuam a publicar ue_auto_height para que possa reposicionar o que fica por baixo.
Largura automática — ib_auto_width #
O mesmo princípio aplicado à largura. Publicada unicamente pelo listbar, o único componente cuja largura natural tem significado.
Uma listbar recolhida numa calha encolhe sozinha e devolve a largura ao expandir-se: ib_auto_width só lhe serve se quiser acompanhar também a largura expandida (a barra ajusta-se então à etiqueta mais comprida).
Eventos de rato ambientais — ib_track_mouse #
Os eventos de rato de alta frequência estão cortados na origem: sem subscrição, o componente não os emite (nada atravessa a ponte para o PowerBuilder).
uo_bouton.ib_track_mouse = true // ativa ue_mouse_enter / ue_mouse_leave / ue_rclicked
Publicados por: button, picture, statictext.
Os eventos discretos (clique, seleção, menu, largada…) são sempre emitidos, sem subscrição.
3.5 Os atalhos de teclado #
Um atalho aciona um componente esteja o foco onde estiver na window — o utilizador não tem de voltar ao botão para o acionar. Qualquer componente visual os aceita, sem nada a ativar.
uo_enregistrer.of_register_shortcut("Ctrl+S")
uo_actualiser.of_register_shortcut("F5")
Escrever um acorde de teclas #
O acorde é uma cadeia livre, normalizada pela biblioteca: as maiúsculas, os espaços e a ordem dos modificadores não têm qualquer importância. "Ctrl+Shift+S", "ctrl + shift + s" e "SHIFT+CTRL+S" designam o mesmo atalho — é impossível registar duas variantes por descuido.
| Elemento | Formas aceites |
|---|---|
| Modificadores | Ctrl (ou Control), Alt, Shift — combináveis, por qualquer ordem |
| Tecla | uma letra A–Z, um algarismo 0–9, F1 … F24, Enter (ou Return), Escape (ou Esc), Delete (ou Del), Insert, Home, End, PageUp, PageDown |
Esta lista é exaustiva: uma tecla ausente (Tab, Espaço, uma tecla do teclado numérico, um sinal de pontuação) não aciona qualquer atalho.
Uma tecla isolada é um acorde válido ("F5"). Uma cadeia vazia retira o atalho do componente.
"Enter"e"Escape"isoladas não se registam como atalhos: estas duas teclas continuam reservadas ao botão predefinido e ao botão de cancelamento (ib_default/ib_canceldo button). Combinadas com um modificador, voltam a ser acordes vulgares ("Ctrl+Enter").
Quem ganha em caso de conflito #
Dois componentes podem pedir o mesmo acorde — algo frequente quando uma window aloja várias zonas com o seu próprio «Guardar». O arbítrio faz-se por esta ordem:
- o componente que tem o foco de teclado prevalece sobre todos os outros: o atalho de uma zona ativa nunca é eclipsado por um vizinho;
- na falta dele, ganha o primeiro registado.
Apenas os componentes visíveis e ativos da window em primeiro plano concorrem. Voltar a registar um acorde num componente que já tinha um substitui-o sem alterar a sua posição: reconfigurar uma window não baralha as prioridades.
Atalhos de item #
A sobrecarga de dois argumentos liga o acorde a um item do componente em vez do componente inteiro — o segundo argumento é o identificador do item:
uo_barre.of_register_shortcut(/*acorde*/ "Ctrl+N", /*item*/ "nouveau")
uo_barre.of_register_shortcut(/*acorde*/ "Ctrl+P", /*item*/ "imprimer")
Retirar os atalhos #
uo_barre.of_clear_shortcuts() // componente E items
of_reset() e a destruição do componente chamam of_clear_shortcuts() por si: um componente que desapareceu nunca mantém um acorde reservado.
A tecla Alt #
A tecla Alt isolada não é capturada: dá o foco ao ribbon, que mostra as suas keytips (ver ribbon). A biblioteca não interceta, portanto, as teclas seguintes — é o ribbon que as lê, como se o utilizador lhe tivesse clicado. Esc ou um segundo Alt devolvem o foco ao controlo abandonado. Se nenhum ribbon da window declarar keytips, Alt mantém o seu comportamento habitual do Windows.
| Membro | Efeito |
|---|---|
of_register_shortcut (string as_chord) | Declara um atalho para o componente; uma cadeia vazia retira-o |
of_register_shortcut (string as_chord, string as_key) | Declara um atalho para um item, designado pelo seu identificador |
of_clear_shortcuts ( ) | Retira todos os atalhos do componente, items incluídos |
3.6 Repor um componente a zero: of_reset() #
of_reset() devolve o componente ao seu estado inicial, como se tivesse acabado de ser carregado:
- o conteúdo é esvaziado (items, páginas, painéis…);
- cada propriedade regressa à sua predefinição (formatação, cores, modo, etiquetas);
- as substituições de estilo e os tooltips definidos na instância são anulados;
- a cache de propriedades do lado do PowerBuilder é esvaziada (as releituras partem novamente das predefinições);
- o estado nativo é igualmente reposto (menu de contexto, modo de apresentação…).
uo_grid.of_reset() // recomecar com uma grelha vazia
// ... depois reconstruir
⚠️ Reutilizar uma instância para apresentar outra coisa sem chamar
of_reset()mantém o estado anterior (uma cor, um modo, uma altura automática). É a causa mais frequente de um «resto de apresentação» inexplicado.
3.7 Diagnóstico #
| Membro | Efeito |
|---|---|
of_is_created ( ) → boolean | O componente nativo existe (runtime presente, anfitrião válido) |
of_is_ready ( ) → boolean | O conteúdo web está carregado (ue_ready já acionado) |
of_get_last_error ( ) → string | Última mensagem de erro detalhada da DLL, após um retorno < 0 |
Códigos de retorno dos métodos of_*:
| Retorno | Significado |
|---|---|
≥ 0 | OK (aplicado ou colocado em fila) |
-2 | Componente não criado (runtime ausente, anfitrião inválido) |
-4 | Operação falhada (captura, escrita de ficheiro…) |
-5 | Argumento inválido (identificador vazio, valor fora dos limites) |
-6 | Runtime WebView2 demasiado antigo para a funcionalidade pedida (impressão) |
3.8 Exportar a representação como imagem #
Qualquer componente sabe exportar-se como imagem, tal como é apresentado:
uo_pivot.of_save_as_png("C:\temp\tableau.png")
uo_pivot.of_save_as_jpg("C:\temp\tableau.jpg")
Para o imprimir em vez de o exportar, ver Imprimir.
Útil para um relatório, um anexo de e-mail ou um registo de incidente. O componente tem de estar criado e o seu conteúdo carregado.
3.9 Ciclo de vida #
- Construção: o webview é criado logo na construção do userobject — indispensável para o alojamento (separadores, painéis acopláveis): um webview criado depois da mudança de elemento pai do respetivo HWND não é apresentado.
- Fila de espera: os comandos são colocados em fila enquanto
ue_readynão for acionado. - Pronto:
ue_ready; a fila é reproduzida pela mesma ordem. - Redimensionamento: automático, o componente acompanha o tamanho do userobject.
- Destruição: ao fechar a window; o webview é libertado, sem qualquer processo órfão.
Deve chamar-se PBT_Warmup() uma vez no arranque da aplicação para que este ciclo seja impercetível (Instalação).
3.10 Boas práticas #
- Definir o tema predefinido e o idioma no objeto de aplicação, antes da abertura da primeira window: os componentes deixam de apresentar qualquer flash de estilo.
- Enquadrar toda a construção volumosa com
of_set_redraw(false)/of_set_redraw(true). - Chamar
of_reset()antes de reutilizar uma instância para outro conteúdo. - Não bloquear a thread de UI com um ciclo PowerScript longo entre a criação e a apresentação: a inicialização do webview precisa do ciclo de mensagens (ver FAQ).