PBToolboxAI v1 ← Site

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 #

EventoAcionado 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_ready não se perdem: são colocados em fila e reproduzidos pela mesma ordem. É, portanto, possível configurar tudo logo no constructor ou no open.

// 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.

ElementoFormas aceites
ModificadoresCtrl (ou Control), Alt, Shift — combináveis, por qualquer ordem
Teclauma letra AZ, um algarismo 09, F1F24, 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_cancel do 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:

  1. o componente que tem o foco de teclado prevalece sobre todos os outros: o atalho de uma zona ativa nunca é eclipsado por um vizinho;
  2. 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.

MembroEfeito
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:

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 #

MembroEfeito
of_is_created ( ) → booleanO componente nativo existe (runtime presente, anfitrião válido)
of_is_ready ( ) → booleanO 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_*:

RetornoSignificado
≥ 0OK (aplicado ou colocado em fila)
-2Componente não criado (runtime ausente, anfitrião inválido)
-4Operação falhada (captura, escrita de ficheiro…)
-5Argumento inválido (identificador vazio, valor fora dos limites)
-6Runtime 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 #

  1. 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.
  2. Fila de espera: os comandos são colocados em fila enquanto ue_ready não for acionado.
  3. Pronto: ue_ready; a fila é reproduzida pela mesma ordem.
  4. Redimensionamento: automático, o componente acompanha o tamanho do userobject.
  5. 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 #


← Primeiros passos · Índice · Temas →