datagrid — u_pbt_datagrid #
← Referência dos componentes · Índice do guia
A grelha moderna de um DataStore: colunas tipadas e células ricas, ordenação, filtros, agrupamento com subtotais, edição no próprio sítio, paginação, origem por janela e exportação CSV — o DataWindow continua a ser o dono dos seus dados.
▶ Ver ao vivo — Aplicação de demonstração, mosaico Data grid: a pré-visualização, o código que o produz e esta página, lado a lado.
Em resumo #
| Userobject | u_pbt_datagrid |
| Classe de items | n_pbt_datagrid_column — uma coluna, obtida com of_column |
| Serve para | Apresentar um DataStore numa grelha moderna — ordenação, filtros, agrupamentos, edição, volumes muito grandes — sem sair do seu DataWindow |
| Limite no modo de demonstração | 100 linhas apresentadas; exportações CSV e Excel desativadas — ver o modo de demonstração |
O posicionamento #
O datagrid não é um substituto da DataWindow: é uma camada de apresentação que se coloca por cima. O SQL, os Retrieve(), os Update() e as impressões mantêm-se — e ganha-se uma grelha moderna para a visualização.
Visa dois pontos cegos da grelha DataWindow clássica:
- a escalabilidade — apenas as linhas visíveis são efetivamente desenhadas, o deslocamento mantém-se fluido em dezenas de milhares de linhas, e o modo por janela suporta centenas de milhares de linhas;
- as células ricas — marca de estado colorida, barra de progresso, minicurva, classificação por estrelas, avatar, múltiplas etiquetas, botão de ação, ligação.
A ligação à base de dados e a atualização permanecem fora do âmbito: pertencem à DataWindow.
O DataStore dos exemplos #
Todos os exemplos desta página — como os da aplicação de demonstração — partem do mesmo DataStore de contas de clientes, uma linha por conta: city, rep (o comercial), status, pipeline (uma percentagem), trend (sete valores mensais escritos "3,5,2,6,7,4,8"), revenue e rating (uma nota em cinco). A grelha chama-se uo_grid na janela, o DataStore ids. Uma linha carregada por of_from_datastore tem como chave o seu RowID no DataStore: não muda quando o DataStore ordena, filtra, insere ou elimina. Um evento devolve-lho, e ids.GetRowFromRowId(Long(as_key)) é o número da linha que designa agora.
Um DataStore só contém valores simples, e isso chega para as células ricas: um número é tudo o que um indicador (RENDERER_PROGRESS) e as estrelas (RENDERER_RATING) precisam, um nome dá um avatar, um texto "3,5,2,6" um minigráfico (RENDERER_SPARKLINE) tal como "vip, b2b" dá etiquetas (RENDERER_TAGS); a cor de uma pastilha (RENDERER_CHIP) dá-se por valor com is_tones.
Início rápido #
// open event of the window : the accounts, retrieved the way your application already does
ids = create datastore
ids.dataobject = "d_accounts"
ids.SetTransObject(SQLCA)
ids.Retrieve()
// 1. The grid reads the columns (typed) and every row of the DataStore
uo_grid.of_from_datastore(/*ads*/ ids)
// 2. The titles are the header texts of the DataWindow ; rename one if you like
uo_grid.of_column(/*key*/ "rep").is_title = "Account manager"
// 3. Rich cells : an avatar, a coloured status, a gauge, a mini chart, stars
uo_grid.of_column(/*key*/ "rep").is_renderer = n_pbt_datagrid_column.RENDERER_AVATAR
uo_grid.of_column(/*key*/ "status").is_renderer = n_pbt_datagrid_column.RENDERER_CHIP
uo_grid.of_column(/*key*/ "status").is_tones = "Active=" + n_pbt_datagrid_column.TONE_SUCCESS + "|At risk=" + n_pbt_datagrid_column.TONE_DANGER
uo_grid.of_column(/*key*/ "pipeline").is_renderer = n_pbt_datagrid_column.RENDERER_PROGRESS
uo_grid.of_column(/*key*/ "trend").is_renderer = n_pbt_datagrid_column.RENDERER_SPARKLINE
uo_grid.of_column(/*key*/ "rating").is_renderer = n_pbt_datagrid_column.RENDERER_RATING
// 4. A total, and the city stays in view
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
// ue_row_clicked event of uo_grid : (string as_key)
// The key of a row loaded by of_from_datastore is its RowID : GetRowFromRowId gives
// the row it designates now, even after a sort or a delete in the DataStore.
wf_open_account(ids.GetRowFromRowId(Long(as_key)))
Propriedades #
| Propriedade | Tipo | Predefinição | Função |
|---|---|---|---|
is_selection_mode | string | SELECT_NONE | Modo de seleção: nenhuma, uma linha, várias (Shift = intervalo, Ctrl = alternar) |
is_density | string | DENSITY_COMFORTABLE | Altura de linha: confortável ou compacta |
is_quick_filter | string | "" | Filtro rápido global: mantém apenas as linhas cujo texto — tal como apresentado (22/09/2026, 1 234,50) ou em bruto — contém este valor. O que o utilizador escreve espera pelo fim da escrita; oculto com uma origem por janelas |
ib_filter_row | boolean | false | Apresenta a linha de introdução de filtro sob os cabeçalhos (equivalente ao botão Filtros) |
ib_context_menu | boolean | true | Menu de contexto integrado numa linha: Copiar, Selecionar tudo, Limpar a seleção, Exportar para CSV, além das suas próprias entradas (of_add_row_menu_item). Ativo por predefinição. Um clique direito fora da seleção desloca-a para a linha visada, um clique direito dentro mantém-na. A false para mostrar o seu próprio menu a partir de ue_row_rclicked |
ib_veto_edits | boolean | false | Pergunta antes de manter um valor introduzido: emite ue_cell_editing, que pode recusar — a célula mantém então o seu valor anterior |
ib_write_back | boolean | false | Escreve cada introdução no DataStore passado a of_from_datastore — SetItem na linha que a chave designa (o seu RowID, encontrado onde está), tipado pela coluna (datas, números, texto, códigos) — antes de ue_cell_edited. O Update continua a ser seu; uma data ou um número esvaziados passam a NULL, e um valor que o DataStore não pode manter (uma linha eliminada entretanto, um valor que SetItem recusa, um texto que não é uma hora) não é mantido: a célula retoma o que o DataStore tem, ue_write_back_failed diz porquê, e ue_cell_edited não é emitido. SetItem não aplica a regra Validation da coluna: verifique um valor em ue_cell_editing (ib_veto_edits) |
ib_detail_on_demand | boolean | false | Detalhe a pedido: cada linha mostra a sua seta, e abri-la (a seta, ou of_expand_row) emite ue_detail_needed — preencha aí o painel com of_fill_detail, abre-se no regresso do evento. Nada preenchido: a linha fica fechada. O detalhe de 5 000 linhas nunca é lido antecipadamente |
is_group_by | string | "" | Agrupa as linhas por uma ou várias colunas, por ordem, as suas chaves unidas por | ("status|city"); cada cabeçalho de grupo tem os subtotais das colunas que têm um total. "" volta a uma lista simples. Relida em direto |
ii_page_size | integer | 100 | Número de linhas por página, uma vez desencadeada a paginação |
il_page_threshold | long | 50000 | Número de linhas a partir do qual a grelha passa a páginas. 0 = paginar sempre, seja qual for o volume |
is_theme_style | string | "" | Estilo visual do componente (constantes THEME_STYLE_*); vazio = o da aplicação, seguido a cada mudança |
is_theme_mode | string | "" | Variante clara ou escura (constantes THEME_MODE_*); vazio = a da aplicação, seguida a cada mudança |
il_theme_accent | long | -1 | Cor de destaque deste componente (-1 = destaque da aplicação, ou o do tema) |
is_tooltip | string | "" | Tooltip simples apresentado ao passar sobre o componente |
is_super_tooltip_title | string | "" | Título do tooltip enriquecido (prevalece sobre is_tooltip) |
is_super_tooltip_text | string | "" | Texto do tooltip enriquecido (aceita marcação enriquecida) |
is_super_tooltip_image | string | "" | Imagem do tooltip enriquecido |
Propriedades de coluna #
Cada coluna é um objeto por direito próprio, obtido por of_column("identificador") — o handle é criado no primeiro acesso e permanece válido a seguir.
// A column is reached by its key ; used once, it fits on one line
uo_grid.of_column(/*key*/ "amount").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
| Propriedade | Tipo | Predefinição | Função |
|---|---|---|---|
is_title | string | a chave | Texto de cabeçalho da coluna; "" volta a mostrar a chave. of_from_datastore deixa os nomes de coluna do DataWindow: dê-lhes aqui um nome para o utilizador |
is_tones | string | "" | Cor de uma pastilha (RENDERER_CHIP) segundo o seu valor, para o texto de um DataStore: pares valor=tom unidos por | ("Active=success|At risk=danger"), tons TONE_*; um valor não listado fica neutro |
ii_width | integer | largura declarada | Largura da coluna, em pixeis |
ib_hidden | boolean | false | Oculta ou volta a apresentar a coluna |
is_pin | string | PIN_NONE | Fixa a coluna à esquerda ou à direita: mantém-se visível durante o deslocamento horizontal |
ib_editable | boolean | false | Autoriza a introdução: duplo clique, escrita, Enter valida, Esc cancela → ue_cell_edited. Um valor que não convém à coluna (letras num número) é mostrado como recusado durante a escrita, e Enter mantém o editor aberto. Uma coluna booleana mostra uma verdadeira caixa de verificação: um clique, Espaço, Enter ou F2 inverte-a de imediato. Escrever um carácter numa célula de texto ou número abre o editor com esse carácter; durante uma edição, Tab e Shift+Tab mantêm o valor e abrem a célula modificável seguinte (anterior) |
is_summary | string | SUMMARY_NONE | Total no rodapé da coluna; SUMMARY_NONE remove-o. SUMMARY_COUNT conta as células que têm um valor, como count() de um DataWindow |
is_renderer | string | RENDERER_NONE | Célula rica aplicada a posteriori; RENDERER_NONE regressa ao texto. RENDERER_BOOL mostra um visto para um valor verdadeiro; RENDERER_CUSTOM lê o valor como texto rico com etiquetas — para uma coluna que o seu código compõe: um valor escrito por um utilizador deve ter os parênteses retos escapados ([[ ]]) |
ii_index | integer | ordem de declaração | Posição da coluna (primeira posição = 1); uma coluna que a grelha não tem relê-se 0 |
is_filter | string | "" | Filtro por coluna. O texto é procurado no que a célula mostra (data formatada, número com máscara) ou no seu valor bruto; numa coluna numérica é reconhecido um operador inicial ("> 1000", "<= 50", "> 1,5" com o separador decimal da língua), numa coluna de data também ("> 22/09/2026", na ordem da língua, ou ISO). Cadeia vazia = filtro removido |
is_format | string | "" | Formato de apresentação, na sintaxe da DataWindow: "#,##0.00", "$#,##0;($#,##0)", "0.0%", "dd/mm/yyyy", "mmmm d, yyyy", "hh:mm", "@@@-@@@@". Como numa DataWindow, a vírgula e o ponto designam os separadores da língua. Cadeia vazia = volta o formato da DataWindow; relê-se (o formato em vigor) |
Constantes #
Devem utilizar-se sempre as constantes em vez das cadeias literais: o IDE completa-as e um erro de escrita torna-se impossível.
| Família | Constantes | Suportadas por |
|---|---|---|
| Tipo de coluna | TYPE_STRING, TYPE_NUMBER, TYPE_INT, TYPE_DATE, TYPE_DATETIME, TYPE_BOOL | o componente (of_add_column) |
| Célula rica | RENDERER_AVATAR, RENDERER_CHIP, RENDERER_PROGRESS, RENDERER_SPARKLINE, RENDERER_RATING, RENDERER_TAGS, RENDERER_BUTTON, RENDERER_LINK, RENDERER_BOOL, RENDERER_CUSTOM | o componente e o handle de coluna (is_renderer) |
| Célula rica: nenhuma | RENDERER_NONE | apenas o handle de coluna (is_renderer) |
| Tom da pastilha | TONE_SUCCESS, TONE_WARN, TONE_DANGER, TONE_INFO, TONE_NEUTRAL | o handle de coluna (is_tones) |
| Modo de seleção | SELECT_NONE, SELECT_SINGLE, SELECT_MULTIPLE | o componente (is_selection_mode) |
| Densidade | DENSITY_COMFORTABLE, DENSITY_COMPACT | o componente (is_density) |
| Total de rodapé | SUMMARY_NONE, SUMMARY_SUM, SUMMARY_AVG, SUMMARY_MIN, SUMMARY_MAX, SUMMARY_COUNT | o handle de coluna (is_summary) |
| Lado de fixação | PIN_NONE, PIN_START, PIN_END (lógicos: START = margem de início de leitura) | o handle de coluna (is_pin) |
As constantes leem-se no objeto que as transporta:
u_pbt_datagrid.SELECT_MULTIPLEpara uma propriedade do componente,n_pbt_datagrid_column.PIN_STARTpara uma propriedade de coluna.
Métodos #
Alimentar a grelha #
| Método | Função | |
|---|---|---|
of_from_datastore (datastore ads) | A ponte DataStore: lê as colunas (nome + tipo PowerBuilder, tipagem automática) e transfere todas as linhas numa só chamada, com o que o DataWindow diz de cada coluna — o seu texto de cabeçalho passa a ser o título, o seu formato de apresentação aplica-se, e uma tabela de códigos (Values, DropDown DataWindow, CheckBox) mostra o valor apresentado enquanto a linha mantém o dado. As colunas chegam pela ordem em que o DataWindow as mostra (o seu X), e uma coluna oculta no painter (Visible = 0) chega oculta: o utilizador volta a mostrá-la pelo botão Colunas. Um campo calculado não é uma coluna do DataStore: não chega; uma DropDown DataWindow cujo filho não tem linhas mostra os códigos. Volte a chamá-la após um Retrieve: as colunas mantêm o que lhes foi definido (título, célula rica, fixação, largura, total) e o seu lugar, o que o DataWindow diz (cabeçalho, formato, tabela de códigos) é relido, e cada valor chega sob a sua própria coluna, seja qual for a ordem que o utilizador lhes deu. A chave de cada linha é o seu RowID: não muda quando o DataStore ordena, filtra, insere ou elimina, e ids.GetRowFromRowId(Long(as_key)) é a linha que designa agora. Devolve 0 uma vez aplicado, -5 quando o DataStore não é válido ou não tem colunas, -2 quando o componente não está criado | |
of_add_column (string as_key, string as_title, string as_type) | Adiciona uma coluna de largura automática, depois das outras: as que já existem mantêm o que lhes foi definido. Para alterar uma coluna depois, use o seu handle (of_column). Devolve 0 uma vez aplicado, -5 quando a chave está vazia, contém / ou ` | , ou nomeia uma coluna que a grelha já tem, -2` quando o componente não está criado |
of_add_column (string as_key, string as_title, string as_type, long al_width) | Idem, com uma largura em pixeis (0 = automática). Devolve 0 uma vez aplicado, -5 quando a chave está vazia, contém / ou ` | , ou nomeia uma coluna que a grelha já tem, -2` quando o componente não está criado |
of_add_column (string as_key, string as_title, string as_type, long al_width, string as_renderer) | Idem, com uma célula rica (RENDERER_*). Devolve 0 uma vez aplicado, -5 quando a chave está vazia, contém / ou ` | , ou nomeia uma coluna que a grelha já tem, -2` quando o componente não está criado |
of_set_columns (string as_columns_json) | Declara todas as colunas de uma só vez, com as respetivas opções detalhadas (formato, fixação, coluna modificável…). Os handles de coluna obtidos antes (of_column) são libertados: volte a obtê-los. Devolve 0 uma vez aplicado, -5 quando o texto não é um array JSON, -2 quando o componente não está criado | |
of_load_rows (string as_rows_json) | Substitui as linhas apresentadas. O DataStore de um of_from_datastore anterior é esquecido: ib_write_back e of_reload_row deixam de o alcançar. Devolve 0 uma vez aplicado, -5 quando o texto não é um array JSON, -2 quando o componente não está criado | |
of_append_rows (string as_rows_json) | Acrescenta linhas a seguir às linhas já apresentadas — deslocamento infinito, chegada em tempo real. Devolve 0 uma vez aplicado, -5 quando o texto não é um array JSON ou linhas dele foram deixadas de fora porque a grelha já tem a sua chave (as outras são acrescentadas), -2 quando o componente não está criado | |
of_update_row (string as_row_json) | Substitui uma linha no lugar: aquela que tem a mesma chave _k. Devolve 0 uma vez aplicado, -5 quando o texto não é um objeto JSON ou a grelha não tem nenhuma linha com essa chave, -2 quando o componente não está criado | |
of_reload_row (long al_row) | Volta a enviar uma linha do DataStore passado a of_from_datastore, lida agora: depois de o seu código a ter alterado. al_row é o seu número de linha hoje; a grelha encontra a linha pelo seu RowID, uma ordenação ou uma eliminação entretanto não mudam nada. Uma linha que a grelha ainda não tem (InsertRow, onde quer que seja) é adicionada depois das outras. Devolve 0 uma vez enviada, -5 quando nenhum DataStore está ligado ou a linha não existe, -2 quando o componente não está criado | |
of_reset_update ( ) | A chamar depois de o seu Update ter sido bem-sucedido: as células modificadas na grelha deixam de estar marcadas (um pequeno canto na cor de destaque). Devolve 0 uma vez enviado, -2 quando o componente não está criado | |
of_remove_row (string as_key) | Remove uma linha, pela sua chave. Para uma linha de um DataStore a chave é o seu RowID: obtenha-a antes de ids.DeleteRow(ll_row), com String(ids.GetRowIdFromRow(ll_row)). Devolve 0 uma vez aplicado, -5 quando a grelha não tem nenhuma linha com esta chave, -2 quando o componente não está criado | |
of_clear_columns ( ) | Esvazia as colunas acumuladas por of_add_column, antes de reconstruir uma grelha. Os handles de coluna obtidos antes (of_column) são libertados: volte a obtê-los. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
Colunas #
| Método | Função |
|---|---|
of_column (string as_key) | O handle de uma coluna (n_pbt_datagrid_column): largura, fixação, ocultação, introdução, total, célula rica, posição, filtro — ver Propriedades de coluna |
Ordenação, filtro, apresentação #
| Método | Função |
|---|---|
of_sort (string as_col, string as_dir) | Ordena por uma só coluna: "asc", "desc" ou "none" (regresso à ordem carregada). Uma coluna com tabela de códigos ordena pelo seu dado, como um DataWindow. Várias colunas: of_sort("city A, revenue D"). Devolve 0 uma vez ordenado, -5 quando a grelha não tem essa coluna ou o sentido não é um dos três, -2 quando o componente não está criado |
of_sort (string as_sort) | Ordena por várias colunas, pela sua ordem: a primeira decide, as seguintes desempatam. as_sort escreve-se como o SetSort de um DataWindow o lê — "city A, revenue D"; asc e desc também são lidos, uma coluna sem sentido é crescente, e "" retira a ordenação (ordem carregada). Devolve 0 uma vez ordenado, -5 para uma coluna que a grelha não tem, outro sentido ou uma coluna nomeada duas vezes, -2 quando o componente não está criado |
of_get_layout ( ) | O que o utilizador organizou, em JSON: as colunas pela sua ordem com largura, fixação e visibilidade, a ordenação (um array ordenado: "sort":[{"col":"city","dir":"asc"},{"col":"revenue","dir":"desc"}]), os filtros tal como escritos, a pesquisa rápida, o agrupamento e a linha de filtros. Para guardar (ficheiro, registo, tabela) e devolver a of_set_layout. Títulos, células ricas e formatos são seus: não constam dele |
of_set_layout (string as_layout_json) | Repõe uma disposição lida por of_get_layout ou recebida por ue_layout_changed. Uma coluna que não conhece (acrescentada entretanto) mantém o seu lugar depois das que ordena; uma coluna que nomeia e que já não existe é ignorada; é emitido ue_layout_changed, como em qualquer mudança da disposição. Uma ordenação escrita como objeto único ("sort":{"col":"city","dir":"asc"}) também é lida. Devolve 0 uma vez aplicada, -5 quando o texto está vazio ou não é um objeto JSON (um ficheiro truncado: nada é enviado), -2 quando o componente não está criado |
of_clear_filters ( ) | Apaga o filtro rápido e todos os filtros por coluna. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
Seleção, detalhe, exportação #
| Método | Função | |
|---|---|---|
of_select_rows (string as_keys_json) | Define a seleção a partir do seu código, por lista de chaves ('["1","4"]'); um array vazio anula toda a seleção, uma chave que a grelha não tem é deixada de fora. Como um clique, emite ue_selection_changed (nada se as mesmas linhas continuarem selecionadas). Devolve 0 uma vez aplicado, -5 quando o texto não é um array JSON, -2 quando o componente não está criado | |
of_selected_keys ( ) | Devolve as chaves selecionadas, como array JSON ('["1","4"]'), lidas na grelha no momento da chamada: uma seleção definida por of_select_rows, ou uma linha retirada entretanto, já é tida em conta | |
of_fill_detail (string as_key, string as_markup) | Painel de detalhe de uma linha, em texto formatado. Devolve 0 uma vez aplicado, -5 quando a grelha não tem nenhuma linha com esta chave, -2 quando o componente não está criado | |
of_expand_row (string as_key) · of_collapse_row (string as_key) | Expande / recolhe o painel de detalhe de uma linha; como o seu chevron, emite ue_row_expanded / ue_row_collapsed (nada se o painel já estiver nesse estado). Devolve 0 uma vez aplicado, -5 quando a grelha não tem nenhuma linha com esta chave, -2 quando o componente não está criado | |
of_expand_node (string as_key) · of_collapse_node (string as_key) | Modo em árvore: expande / recolhe um nó (as linhas filhas levam _parent). Devolve 0 uma vez aplicado, -5 quando a grelha não tem nenhuma linha com esta chave, -2 quando o componente não está criado | |
of_export_csv (string as_path) | Escreve o que a grelha mostra (filtros, ordenação, colunas visíveis) num ficheiro CSV: UTF-8 com BOM, separador ponto e vírgula — o gémeo da exportação do crosstab. A DLL escreve o ficheiro, ue_csv_saved confirma. Recusado sem licença. Devolve 0 uma vez pedido, -5 quando o caminho está vazio, -2 quando o componente não está criado | |
of_export_xlsx (string as_path) | Escreve o que a grelha mostra (filtros, ordenação, colunas visíveis) num livro do Excel (.xlsx): os números continuam números, com o formato da sua coluna, a linha de cabeçalho a negrito. A DLL escreve o ficheiro, ue_xlsx_saved confirma; um caminho relativo é escrito na pasta onde a aplicação arrancou. Recusado sem licença e com uma fonte por janelas. Devolve 0 uma vez pedido, -5 quando o caminho está vazio, -2 quando o componente não está criado | |
of_add_row_menu_item (string as_key, string as_label) | Acrescenta uma das suas entradas ao menu de contexto de linha, sob as integradas; a escolha volta em ue_row_menu_clicked com esta chave, uma etiqueta vazia mostra a chave. Devolve 0 uma vez acrescentada, -5 quando a chave está vazia, contém / ou ` | `, ou já é uma das suas entradas |
of_add_row_menu_separator ( ) | Um separador entre dois grupos das suas entradas. Devolve 0 | |
of_clear_row_menu ( ) | Retira as suas entradas: o menu de linha volta apenas às entradas integradas. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
Volumes muito grandes #
| Método | Função |
|---|---|
of_open_source (long al_total) | Declara uma origem de al_total linhas sem as construir: a grelha solicita apenas aquelas que tem de apresentar, através de ue_rows_needed. As chaves são então posições na sua origem; o DataStore de um of_from_datastore anterior é esquecido. A pesquisa rápida e a linha de filtros ficam ocultas (a grelha só tem as linhas no ecrã); uma ordenação escolhida pelo utilizador chega-lhe por ue_sort_changed: ordene a sua origem, a grelha volta a pedir as suas linhas. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
of_supply_rows (long al_from, string as_rows_json) | Resposta a ue_rows_needed: o lote de linhas é colocado a partir da linha al_from, contada a partir de 1 como as de um DataStore. Devolve 0 uma vez aplicado, -5 quando o texto não é um array JSON, -2 quando o componente não está criado |
of_clear_source ( ) | Abandona o modo por janela e regressa às linhas carregadas em memória. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
of_go_to_page (long al_page) | Apresenta uma dada página (a primeira = 1). Sem efeito enquanto a paginação não for desencadeada. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
of_supply_grand_totals (string as_values_json) | Define o total geral, que o programador calcula: '{"ca":128400000,"quantity":51230}'. Uma cadeia vazia retira-o. Devolve 0 uma vez aplicado, -5 quando o texto não é um objeto JSON, -2 quando o componente não está criado |
Comuns #
| Método | Função |
|---|---|
of_reset ( ) | Esvazia colunas e linhas, e repõe o componente no seu estado inicial. Devolve 0 uma vez aplicado, -2 quando o componente não está criado |
of_set_redraw (boolean) | Agrupa uma rajada de alterações numa única representação. Devolve 0 |
of_save_as_png (string) · of_save_as_jpg (string) | Exporta a representação como imagem. Devolve 0 uma vez escrita a imagem, -2 não criado, -4 captura falhada, -5 caminho vazio |
Eventos #
| Evento | Acionado quando |
|---|---|
ue_row_clicked (string as_key) | Uma linha é clicada |
ue_row_dblclicked (string as_key, string as_col) | Uma linha recebe um duplo clique: o gesto que abre uma ficha. as_col é a coluna sob o ponteiro. Numa célula modificável o duplo clique abre o editor e não lança este evento |
ue_cell_clicked (string as_key, string as_col) | Uma célula é clicada |
ue_selection_changed (string as_keys_json) | A seleção muda: um clique seleciona apenas essa linha, Ctrl+clique acrescenta ou retira uma, Shift+clique toma um intervalo, e of_select_rows faz o mesmo a partir do seu código; as_keys_json é o array JSON das chaves selecionadas ('["1","4"]'). Uma seleção que o seu código esvazia (um recarregamento, SELECT_NONE) também é dita |
ue_sort_changed (string as_col, string as_dir, string as_sort) | A ordenação mudou: um clique num cabeçalho (Shift+clique acrescenta uma coluna à ordenação), o menu de uma coluna, ou of_sort — uma ordem do código emite o evento como um gesto; nada quando a ordenação se mantém. as_col / as_dir: a coluna em causa e o seu sentido agora ("none" uma vez fora da ordenação); as_sort: a ordenação inteira, as colunas pela sua ordem, escrita como SetSort a lê ("city A, revenue D", "" para nenhuma). Com uma fonte em janela (of_open_source), ordene o seu DataStore com ela — ids.SetSort(as_sort) e depois ids.Sort(): a grelha volta então a pedir as suas linhas pela nova ordem |
ue_action_clicked (string as_key, string as_col, string as_action) | Um botão colocado numa célula (RENDERER_BUTTON) é clicado |
ue_row_expanded (string as_key) | Uma linha mestre-detalhe é expandida, pelo seu chevron ou por of_expand_row — o momento certo para alimentar o seu detalhe de imediato |
ue_row_collapsed (string as_key) | Uma linha mestre-detalhe é recolhida, pelo seu chevron ou por of_collapse_row |
ue_detail_needed (string as_key) | Com ib_detail_on_demand: uma linha que ainda não tem detalhe está a ser aberta (a sua seta, ou of_expand_row). Preencha-a aqui com of_fill_detail(as_key, …): o painel abre-se no regresso do evento; nada preenchido, a linha fica fechada |
ue_filter_changed (string as_filters_json) | O utilizador introduziu um filtro, na pesquisa rápida ou na linha de filtro por coluna (a pesquisa: quando a escrita para). as_filters_json diz cada filtro tal como escrito e a pesquisa — {"filters":{"revenue":"> 1000"},"quick":"bos"}: os textos que is_filter e is_quick_filter retomam tal como estão |
ue_cell_edited (string as_key, string as_col, string as_value) | Uma célula modificável é validada com um novo valor; as_value é esse valor em texto. Com ib_veto_edits, só depois de ue_cell_editing o ter aceitado. Com ib_write_back, um valor que o DataStore recusa não é mantido: a célula volta atrás, ue_write_back_failed diz porquê, e este evento não é emitido |
ue_cell_editing (string as_key, string as_col, string as_value) | Antes de um valor introduzido ser mantido, só se ib_veto_edits for verdadeiro. Devolva false para deixar o valor anterior na célula (ue_cell_edited não é então emitido); true por predefinição |
ue_write_back_failed (string as_key, string as_col, string as_value, string as_reason) | Com ib_write_back: o DataStore não pôde manter um valor introduzido (a sua linha eliminada desde o carregamento, um valor que SetItem recusa, um texto que não é uma hora). A célula retomou o que o DataStore tem e ue_cell_edited não foi emitido; as_reason diz porquê — para avisar o utilizador, ou recarregar a linha |
ue_layout_changed (string as_layout_json) | A disposição mudou, seja pelo utilizador ou pelo seu código: uma coluna redimensionada, deslocada, fixada ou ocultada, a ordenação, os filtros, a pesquisa rápida, o agrupamento, a linha de filtros — of_set_layout incluído. Nada é emitido quando nada muda. as_layout_json é a disposição inteira, tal como of_get_layout a devolve: guarde-a e depois devolva-a a of_set_layout |
ue_rows_needed (long al_from, long al_to) | Modo por janela: a grelha pede as linhas al_from a al_to, incluídas, contadas a partir de 1 — os números de linha de um DataStore. Responda com of_supply_rows |
ue_page_changed (long al_page, long al_pages) | A página apresentada muda, através dos botões de paginação ou de of_go_to_page. al_page é a página atual (a primeira = 1), al_pages o número total de páginas. Apenas informa: com uma origem por janelas as linhas da nova página são pedidas por ue_rows_needed — responda a esse, não aos dois |
ue_csv_saved (string as_path, boolean ab_ok, string as_error) | O CSV pedido por of_export_csv — ou pela entrada Exportar para CSV do menu de linha, que pede o ficheiro ao utilizador — foi escrito, ou não: ab_ok, e as_error diz porquê |
ue_xlsx_saved (string as_path, boolean ab_ok, string as_error) | O livro pedido por of_export_xlsx foi escrito — ou não: ab_ok, e as_error diz porquê. as_path é o ficheiro escrito, um caminho relativo resolvido |
ue_copy (string as_tsv) | O utilizador premiu Ctrl+C. as_tsv contém as linhas selecionadas com a respetiva linha de cabeçalho, ou apenas a célula com o foco quando nada está selecionado |
ue_row_rclicked (string as_key, string as_col, long al_x, long al_y) | Uma linha recebeu um clique direito (ou a tecla Menu / Shift+F10 premida sobre ela). Lançado quer o menu integrado esteja ativo quer não. al_x / al_y são píxeis de ecrã, não unidades PowerBuilder: para colocar o seu próprio menu onde o utilizador apontou, use PopMenu(PointerX(), PointerY()) na sua janela |
ue_row_menu_clicked (string as_menu_key, string as_row_key, string as_keys_json) | Uma das suas entradas (of_add_row_menu_item) foi escolhida: as_menu_key é a sua chave, as_row_key a linha sobre a qual o menu foi aberto; as_keys_json é a seleção inteira, sobre a qual uma ação de lote deve trabalhar |
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) |
O que o utilizador pode fazer sem uma linha de código #
A grelha integra a sua própria barra de ferramentas e os seus menus de cabeçalho. Nada disto exige código da sua parte:
- ordenar clicando num cabeçalho: crescente, decrescente, nenhum — só por essa coluna; Shift+clique acrescenta-a à ordenação depois das outras (se já lá está, passa-a de crescente a decrescente e depois retira-a), e cada seta mostra então a sua ordem (1 decide, 2 desempata…);
- filtrar rapidamente pela zona de pesquisa, ou coluna a coluna pelo botão Filtros, que apresenta uma linha de introdução sob os cabeçalhos;
- escolher as colunas visíveis pelo botão Colunas;
- redimensionar uma coluna arrastando a margem do respetivo cabeçalho;
- reordenar as colunas arrastando o respetivo cabeçalho;
- fixar ou ocultar uma coluna através do menu de contexto do respetivo cabeçalho;
- selecionar uma linha, um intervalo (Shift) ou um conjunto (Ctrl);
- agir sobre uma linha através do respetivo menu de contexto: copiar, selecionar tudo, limpar a seleção, exportar para CSV — e as entradas que lhe acrescentar.
Cada alteração da disposição volta em ue_layout_changed: larguras, ordem, colunas fixadas ou ocultas. Guarde-a e devolva-a com uma única chamada a of_set_layout na próxima abertura; of_get_layout relê-a a qualquer momento.
No teclado — a grelha é uma única paragem de tabulação. Uma vez alcançada, percorre-se inteiramente pelo teclado:
| Tecla | Efeito |
|---|---|
| Setas | Deslocam a célula com o foco, célula a célula |
| Home / End | Primeira / última coluna da linha |
| Ctrl+Home / Ctrl+End | Primeira / última célula da grelha |
| Page Up / Page Down | Deslocam-se um ecrã, seguindo a altura real da vista |
| Shift + setas | Estendem a seleção a partir da âncora (modo SELECT_MULTIPLE) |
| Espaço | Seleciona ou desseleciona a linha com o foco e coloca aí a âncora; numa caixa de verificação editável, inverte-a |
| Enter ou F2 | Passa a célula a edição se a sua coluna for editável; uma caixa de verificação inverte-se de imediato |
| Um carácter | Numa célula de texto ou número modificável, abre o editor com esse carácter, como uma folha de cálculo |
| Tab / Shift+Tab (em edição) | Mantém o valor e abre a célula modificável seguinte (anterior), a linha seguinte no fim de uma linha |
| Ctrl+C | Copia a seleção — ver ue_copy |
A célula com o foco é contornada por um filete da cor de destaque e anunciada aos leitores de ecrã através de aria-activedescendant. O foco sobrevive ao deslocamento: sendo a grelha virtualizada, é mantido em memória e reposto após cada renderização. Desaparece, no entanto, se a sua linha sair da vista por uma ordenação ou um filtro.
⚠️ A área de transferência do navegador pode ser recusada numa WebView alojada. É por isso que
ue_copylhe devolve o texto: coloque-o você mesmo comClipBoard(as_tsv)para ter a certeza do resultado.
Exemplos #
Contas de clientes em poucas linhas #
// ids : the accounts DataStore (see above). One repaint for the whole setup.
uo_grid.of_set_redraw(/*on*/ false)
// 1. The grid reads the columns (typed) and every row of the DataStore
uo_grid.of_from_datastore(/*ads*/ ids)
// 2. The titles are the header texts of the DataWindow ; rename one if you like
uo_grid.of_column(/*key*/ "rep").is_title = "Account manager"
// 3. Rich cells : an avatar, a coloured status, a gauge, a mini chart, stars
uo_grid.of_column(/*key*/ "rep").is_renderer = n_pbt_datagrid_column.RENDERER_AVATAR
uo_grid.of_column(/*key*/ "status").is_renderer = n_pbt_datagrid_column.RENDERER_CHIP
uo_grid.of_column(/*key*/ "status").is_tones = "Active=" + n_pbt_datagrid_column.TONE_SUCCESS + "|At risk=" + n_pbt_datagrid_column.TONE_DANGER
uo_grid.of_column(/*key*/ "pipeline").is_renderer = n_pbt_datagrid_column.RENDERER_PROGRESS
uo_grid.of_column(/*key*/ "trend").is_renderer = n_pbt_datagrid_column.RENDERER_SPARKLINE
uo_grid.of_column(/*key*/ "rating").is_renderer = n_pbt_datagrid_column.RENDERER_RATING
// A total, a column that stays in view, several rows selectable
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
uo_grid.of_column(/*key*/ "city").is_pin = n_pbt_datagrid_column.PIN_START
uo_grid.is_selection_mode = u_pbt_datagrid.SELECT_MULTIPLE
uo_grid.of_set_redraw(/*on*/ true)
Agrupar por estado e depois por cidade #
// The subtotal every group header shows
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
// Two levels : the status, then the city inside it ; "" goes back to a flat list
uo_grid.is_group_by = "status|city"
// The rating stays in view on the right
uo_grid.of_column(/*key*/ "rating").is_pin = n_pbt_datagrid_column.PIN_END
Filtrar a partir do seu código #
// The filter row under the headers : the user types in it
uo_grid.ib_filter_row = true
// Only the accounts in Paris, and only those above one million
uo_grid.is_quick_filter = "Paris"
uo_grid.of_column(/*key*/ "revenue").is_filter = "> 1000000"
Ordenar por várias colunas #
A ordenação escreve-se como a de um DataWindow: a primeira coluna decide, as seguintes desempatam. O utilizador faz o mesmo com o rato com Shift+clique nos cabeçalhos; um clique simples recomeça a partir de uma só coluna.
// City first, then the largest revenue in each city
uo_grid.of_sort(/*sort*/ "city A, revenue D")
O que a grelha lê na DataWindow #
of_from_datastore não leva só os dados: o texto de cabeçalho de cada coluna (<coluna>_t) torna-se o seu título, o seu formato de apresentação (Format, ou a máscara de um EditMask) aplica-se, e uma tabela de códigos — os Values de um Edit, de uma DDLB ou de botões de opção, uma DropDown DataWindow, uma CheckBox — mostra o valor apresentado (Active) enquanto a linha mantém o dado (A). Ordena-se e pesquisa-se sobre o que se vê; uma coluna com tabela de códigos edita-se através de uma lista, e volta o dado.
// The grid reads titles, formats and code tables in the DataWindow
uo_grid.of_from_datastore(/*ads*/ ids)
// A format of your own on one column, in the DataWindow's syntax
uo_grid.of_column(/*key*/ "revenue").is_format = "$#,##0.00;($#,##0.00)"
// The rating is picked in its code table (Poor to Excellent) ; the number goes into the DataStore
uo_grid.of_column(/*key*/ "rating").ib_editable = true
uo_grid.ib_write_back = true
// Your code changed a row of the DataStore : show it again
ids.SetItem(12, "rating", 5)
uo_grid.of_reload_row(/*row*/ 12)
Editar no próprio sítio, gravar no DataStore #
A grelha edita, o DataStore guarda a verdade: com ib_write_back, cada introdução é escrita nele na linha que a chave designa (o seu RowID, encontrado onde está), tipada pela coluna, antes de ue_cell_edited — e o indicador acompanha. Uma célula modificada mantém um pequeno canto na cor de destaque até of_reset_update.
// The pipelines can be edited : double-click, type a percentage, Enter
uo_grid.of_column(/*key*/ "pipeline").ib_editable = true
// Every edit goes into the DataStore itself, on the row the key designates
uo_grid.ib_write_back = true
Uma coluna booleana tornada editável (TYPE_BOOL, ou uma coluna CheckBox de um DataWindow lida por of_from_datastore) mostra uma verdadeira caixa de verificação em cada célula: um clique, Espaço, Enter ou F2 inverte-a de imediato — sem editor de texto, e um duplo clique não a inverte duas vezes. A célula recebe o valor do outro estado — true/false, ou os valores ON/OFF da CheckBox do DataWindow — pelo mesmo caminho que uma introdução: veto ib_veto_edits / ue_cell_editing, depois ue_cell_edited, marca «modificada» e ib_write_back. Só de leitura, uma coluna booleana mantém o seu visto ✓.
// A yes/no column the user ticks : a check box in every cell
uo_grid.of_add_column(/*key*/ "vip", /*title*/ "VIP", /*type*/ u_pbt_datagrid.TYPE_BOOL)
uo_grid.of_column(/*key*/ "vip").ib_editable = true
// Saving stays with the DataStore : when the user confirms
if ids.Update() = 1 then
COMMIT USING SQLCA;
// the edited cells are no longer marked as modified
uo_grid.of_reset_update()
else
ROLLBACK USING SQLCA;
end if
Uma linha expansível, escrita a partir do DataStore #
// Local variables
long ll_row
// A detail panel for the first 20 accounts, written from their DataStore row
for ll_row = 1 to 20
uo_grid.of_fill_detail(/*key*/ String(ll_row), /*markup*/ "[b]" + ids.GetItemString(ll_row, "rep") + "[/b] follows the " + ids.GetItemString(ll_row, "city") + " account")
next
// The first one is open right away ; the chevron opens the others
uo_grid.of_expand_row(/*key*/ "1")
Páginas em vez de um deslocamento, e o total de tudo #
Uma vez paginada, a grelha só contém uma página: o seu rodapé totaliza a página. O total de todas as contas é o DataStore que o tem.
// Local variables
n_pbt_json lnv_totals
double ld_revenue
long ll_row
// Pages of 25 rows past 100 rows ; the footer totals the page
uo_grid.ii_page_size = 25
uo_grid.il_page_threshold = 100
uo_grid.of_column(/*key*/ "revenue").is_summary = n_pbt_datagrid_column.SUMMARY_SUM
// The grand total of ALL the accounts, from the DataStore
for ll_row = 1 to ids.RowCount()
ld_revenue = ld_revenue + ids.GetItemDecimal(ll_row, "revenue")
next
lnv_totals.of_set_number(/*path*/ "revenue", /*value*/ ld_revenue)
uo_grid.of_supply_grand_totals(/*values_json*/ lnv_totals.of_text())
Uma origem que a grelha nunca contém inteira #
Para centenas de milhares de linhas, a grelha só conhece o seu número e pede as que mostra. É aqui que a sua aplicação lê da base de dados a fatia pedida; os números de linha começam em 1, como os do DataStore.
// The grid only learns HOW MANY rows exist ; it asks for the ones on screen
uo_grid.of_open_source(/*total*/ ids.RowCount())
// ue_rows_needed event of uo_grid : (long al_from, long al_to)
// Rows al_from to al_to, both included, counted from 1 like the DataStore
n_pbt_json lnv_row
string ls_rows
long ll_row
// One JSON row per DataStore row asked for, its key being the row number
ls_rows = "["
for ll_row = al_from to Min(al_to, ids.RowCount())
lnv_row.of_clear()
lnv_row.of_set_string(/*path*/ "_k", /*value*/ String(ll_row))
lnv_row.of_set_string(/*path*/ "city", /*value*/ ids.GetItemString(ll_row, "city"))
lnv_row.of_set_string(/*path*/ "rep", /*value*/ ids.GetItemString(ll_row, "rep"))
lnv_row.of_set_string(/*path*/ "trend", /*value*/ ids.GetItemString(ll_row, "trend"))
lnv_row.of_set_number(/*path*/ "revenue", /*value*/ Double(ids.GetItemDecimal(ll_row, "revenue")))
if ll_row > al_from then ls_rows = ls_rows + ","
ls_rows = ls_rows + lnv_row.of_text()
next
uo_grid.of_supply_rows(/*from*/ al_from, /*rows_json*/ ls_rows + "]")
// ue_sort_changed event of uo_grid : (string as_col, string as_dir, string as_sort)
// as_sort is the whole sort, written as SetSort reads it ("" for none) :
// sort the source with it, the grid then asks for its rows again
ids.SetSort(as_sort)
ids.Sort()
Exportar o que é mostrado #
// What is shown - filters, sort, visible columns - to a CSV file
uo_grid.of_export_csv(/*path*/ "C:\exports\accounts.csv")
// ue_csv_saved event of uo_grid : (string as_path, boolean ab_ok, string as_error)
if ab_ok then
st_status.Text = "Written : " + as_path
else
st_status.Text = as_error
end if
As suas entradas no menu de linha #
// The row menu, entry by entry
uo_grid.of_add_row_menu_item(/*key*/ "open", /*label*/ "Open the account")
uo_grid.of_add_row_menu_separator()
uo_grid.of_add_row_menu_item(/*key*/ "call", /*label*/ "Call the sales rep")
// ue_row_menu_clicked event of uo_grid : (string as_menu_key, string as_row_key, string as_keys_json)
choose case as_menu_key
case "open"
wf_open_account(Long(as_row_key))
case "call"
wf_call(ids.GetItemString(Long(as_row_key), "rep"))
end choose
Reagir à seleção #
// ue_selection_changed event of uo_grid : (string as_keys_json)
// '["3","7"]' : the RowIDs of the selected accounts (ids.GetRowFromRowId gives their rows)
cb_delete.Enabled = (Pos(as_keys_json, "[]") = 0)
Lembrar a disposição do utilizador #
// ue_layout_changed event of uo_grid : (string as_layout_json)
// Order, widths, pins, hidden columns, sort, filters, grouping : keep it
SetProfileString(gs_ini, "grids", "accounts", as_layout_json)
// open event of the window, once the grid is filled : the layout of last time
uo_grid.of_set_layout(/*layout_json*/ ProfileString(gs_ini, "grids", "accounts", ""))
Boas práticas #
- Enquadre a construção de uma grelha com
of_set_redraw(false)/of_set_redraw(true): as colunas e as linhas aparecem de uma só vez, sem cintilação. - Chame
of_reset()antes de reconstruir uma grelha: sem ele, as colunas já declaradas porof_add_columnacrescentam-se às novas. of_from_datastoredá a cada linha o seu RowID como chave: é ele que viaja em todos os eventos, eids.GetRowFromRowId(Long(as_key))encontra a linha mesmo após uma ordenação ou uma eliminação no DataStore. As linhas que carrega em JSON levam uma chave_kdistinta.- A grelha edita, o seu DataStore grava:
ue_cell_edited→SetItem, depoisUpdate()quando o utilizador confirma. O componente não faz nemUpdate()nem impressão. - Para além de algumas dezenas de milhares de linhas, é preferível passar ao modo por janela em vez de transferir tudo: a memória e o tempo de abertura ressentem-se de imediato.
- Assim que a grelha pagina, acompanhe o total de página com um
of_supply_grand_totals: sem ele, o utilizador lê um total parcial onde espera o total de tudo. - Reserve as células ricas para as colunas que ajudam realmente a ler: três colunas ricas em doze prendem o olhar, doze em doze cansam-no.
- Para analisar e cruzar em vez de listar, o adequado é crosstab.
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.
| Membros | Função | Detalhado em |
|---|---|---|
of_count · of_keys_at · of_has | Percorrer o que o componente contém | 3.2 Os items |
of_reset | Repor o componente a zero | 3.6 Repor um componente a zero: of_reset() |
of_register_shortcut · of_clear_shortcuts | Atalhos de teclado do componente | 3.5 Os atalhos de teclado |
of_is_created · of_is_ready · of_get_last_error | Se nasceu, se está pronto, o que falhou | 3.7 Diagnóstico |
of_save_as_png · of_save_as_jpg | Exportar a renderização como imagem | 3.8 Exportar a representação como imagem |
of_set_redraw | Agrupar as alterações num único repinte | 3.10 Boas práticas |
of_preload_icons | Ícones mostrados sem atraso | Apresentação instantânea: of_icon |
of_set_translation | Traduzir uma legenda do componente | 5.2 Adaptar uma etiqueta: of_set_translation |
of_focus_webview | Dar o foco ao componente | 6.4 Teclado e focus |
of_print · of_print_to_pdf | Imprimir, ou escrever um PDF | 6.9 Imprimir |
of_set_property · of_get_property · of_component_name | Controlar uma propriedade pelo nome | 3.1 O motor de propriedades |
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.