PBToolboxAI v5 ← Site

crosstab — u_pbt_crosstab #

← Referência dos componentes · Índice do guia

Tabela dinâmica completa: zonas de linhas / colunas / valores alimentadas a partir de um DataStore, agregações, filtros, formatação condicional, agrupamento de datas, medidas calculadas e exportações CSV / Excel.

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


Em resumo #

Userobjectu_pbt_crosstab
Classe de itemsn_pbt_crosstab_field (um campo, através de of_field) · n_pbt_crosstab_value (um valor da zona Valores, através de of_value)
Serve paraDar aos utilizadores uma análise cruzada dos dados, que eles próprios reorganizam, sem escrever SQL nem recorrer ao Excel
Limite no modo de demonstração500 linhas de origem processadas — of_get_cell_value e of_get_cell_rows leem essas 500 linhas, os mesmos valores que no ecrã; exportações CSV e Excel e cópia (Ctrl+C) desativadas — ver o modo de demonstração

O princípio #

O componente recebe um conjunto de dados plano — um DataStore, ou seja, qualquer consulta já escrita na aplicação. O crosstab trata do resto: deduz a lista dos campos, que devem ser distribuídos por quatro zonas.

ZonaO que contémEfeito
LinhasCampos de agrupamentoUm nível de linhas por campo, recolhível
ColunasCampos de agrupamentoUm nível de cabeçalhos de coluna por campo
ValoresCampos numéricos e a respetiva agregaçãoO que é calculado nas células
FiltrosCampos de seleçãoUm filtro acima da tabela, aplicado a tudo

Todo o cálculo é feito no componente: uma vez transmitidos os dados, reorganizar a tabela não desencadeia qualquer ida e volta à base de dados nem ao PowerBuilder.


Início rápido #

// event open de la fenetre
// Local variables
datastore lds
lds = create datastore
lds.dataobject = "d_sales"
lds.SetTransObject(SQLCA)
lds.Retrieve()

// 1. Transmitir os dados: os campos sao deduzidos das colunas
uo_crosstab.of_from_datastore(/*ads*/ lds)

// 2. Distribuir os campos pelas zonas
uo_crosstab.of_add_row_field(/*field*/ "region")
uo_crosstab.of_add_col_field(/*field*/ "year")
uo_crosstab.of_add_value_field(/*field*/ "amount", /*agg*/ uo_crosstab.AGG_SUM)

// 3. Apresentar: formato dos montantes e totais gerais
uo_crosstab.of_field(/*field*/ "amount").is_format = "$#,##0"
uo_crosstab.ib_row_grand_total = true
uo_crosstab.ib_col_grand_total = true
// event ue_cell_double_clicked de uo_crosstab : (string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, double ad_value)
// O utilizador quer o detalhe por tras de um numero: abrir a lista correspondente.
of_open_detail(as_row_tuple_json, as_col_tuple_json)

Constantes #

ConstanteValorPara
TOTALS_BOTTOM · TOTALS_TOP"bottom" "top"is_totals_position
VALUES_COLS · VALUES_ROWS"cols" "rows"is_values_axis
THOUSANDS_LOCALE · THOUSANDS_SPACE · THOUSANDS_NONE"locale" "space" "none"is_thousands
AGG_SUM · AGG_COUNT · AGG_COUNT_ROWS · AGG_DISTINCT_COUNT"sum" "count" "countrows" "dcount"of_add_value_field · is_agg
AGG_AVG · AGG_MIN · AGG_MAX"avg" "min" "max"of_add_value_field · is_agg
VALUEFILTER_TOP · VALUEFILTER_BOTTOM"top" "bottom"of_set_value_filter
VALUEFILTER_GT · VALUEFILTER_LT · VALUEFILTER_BETWEEN"gt" "lt" "between"of_set_value_filter
LABEL_GT · LABEL_LT · LABEL_BETWEEN"gt" "lt" "between"of_set_label_filter
LABEL_CONTAINS · LABEL_BEGINS · LABEL_ENDS"contains" "begins" "ends"of_set_label_filter
LABEL_BEFORE · LABEL_AFTER"before" "after"of_set_label_filter
DATE_YEAR · DATE_QUARTER · DATE_MONTH"year" "quarter" "month"of_group_date_field

As constantes de agregação, de filtro, de data e de separador leem-se no componente: uo_crosstab.AGG_SUM. As de um campo ou de um valor (SHOW_*, CF_*) leem-se na classe do seu handle: n_pbt_crosstab_field.CF_SCALE, n_pbt_crosstab_value.SHOW_PCT_GRAND. AGG_COUNT conta os valores não vazios, como a Contagem do Excel; AGG_COUNT_ROWS conta as linhas, vazias incluídas.


Propriedades #

PropriedadeTipoPredefiniçãoFunção
is_totals_positionstring"bottom"Onde se coloca a linha de total geral: TOTALS_BOTTOM (no rodapé, predefinição) ou TOTALS_TOP (no topo, logo abaixo dos cabeçalhos). Só o total geral se desloca: o subtotal de um grupo fica na linha do grupo
is_values_axisstring"cols"Orientação das medidas quando existe mais do que uma: VALUES_COLS (lado a lado em colunas, predefinição) ou VALUES_ROWS (empilhadas em linhas)
is_currency_symbolstring""A moeda que o menu Formato do número de um chip de valor propõe, ao lado de « Sem símbolo » e « % ». Vazio = a da língua de apresentação ($ em inglês, € nas restantes)
is_thousandsstring"locale"Separador de milhares dos valores que não têm formato próprio (is_format vazio e nenhum Format na coluna do DataWindow) — a mesma definição que o menu Opções da grelha: THOUSANDS_LOCALE (o da língua de apresentação, predefinição), THOUSANDS_SPACE, THOUSANDS_NONE, ou o próprio separador (",", ".", " ")
ib_field_listbooleantrueMostra o painel de campos, onde o utilizador reorganiza a tabela com o rato
ib_row_subtotalsbooleantrueMostra o subtotal de cada grupo de linhas, escrito na linha do próprio grupo, acima dos seus membros; desativado, essa linha mantém o rótulo sem valor
ib_col_subtotalsbooleantrueMostra um subtotal por grupo de colunas
ib_row_grand_totalbooleantrueMostra a linha de total geral sob a tabela (a gémea de ib_col_grand_total)
ib_col_grand_totalbooleantrueMostra a coluna de total geral após a tabela (a gémea de ib_row_grand_total). Sem campo em Colunas não há coluna de total — a única coluna de valores É o total — e a propriedade mantém o seu valor para quando um campo lá entrar. Com várias medidas, a coluna Total tem um cabeçalho « Total » e depois um cabeçalho por medida, ordenável
ib_copy_headersbooleantrueCtrl+C copia os cabeçalhos com as células selecionadas: os nomes das colunas numa primeira linha (a medida só é nomeada se a tabela a mostrar: vários valores, ou nenhum campo em Colunas) e o membro de cada linha — o seu caminho completo, « Nord / Lille » — numa primeira coluna, cujo canto traz os nomes dos campos em linhas (« region / ville »). Uma colagem numa folha de cálculo diz assim o que são os valores. false copia apenas os valores. Lida em direto, reposta a true por of_reset
ib_enabledbooleantrueEsbatido: a grelha continua a mostrar os seus valores — uma tabela dinâmica vazia não é o mesmo que uma desligada pela aplicação — mas deixa de responder ao ponteiro
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 um campo #

of_field (string as_field) devolve o handle de um campo: obtém-se uma vez e, a partir daí, o campo é controlado através das suas propriedades. O handle é criado na primeira chamada e reutilizado depois.

PropriedadeTipoPredefiniçãoFunção
is_labelstringcabeçalho do DataWindowEtiqueta legível do campo ("amount" → "Volume de negócios"). Por defeito o texto de cabeçalho da coluna no DataWindow, senão o seu nome; uma cadeia vazia repõe-no. Definida pelo seu código, sobrevive a of_from_datastore
is_showstring"normal"O que a célula apresenta: "normal", "pctGrand" (% do total geral), "pctRow" (% da linha), "pctCol" (% da coluna), "running" (acumulado), "diff" (diferença face ao anterior)
is_conditional_formattingstring"none"Formatação condicional: CF_NONE, CF_SCALE (escala de cores), CF_BARS (barras na célula) ou CF_ICONS (uma seta por terço: subida, estável, descida)
is_formatstringFormat da colunaFormato de apresentação dos valores do campo, um formato de apresentação PowerBuilder ("#,##0.00", "$#,##0;($#,##0)", "0.0%"), escrito com os separadores da língua de apresentação. Vazio = o Format da coluna do DataWindow, lido por of_from_datastore; sem um nem outro, is_thousands e no máximo duas casas decimais. Relida: o formato em vigor, o definido ou senão o da coluna

Os valores de is_show e de is_conditional_formatting estão também disponíveis como constantes no handle (SHOW_PCT_COL, CF_SCALE…). Definidos no campo, is_show, is_conditional_formatting e is_format valem para todos os seus valores da zona Valores e para os que lá entrarem depois — definidos antes de o campo estar em Valores, são guardados, relidos tal como definidos e aplicados à sua chegada. Para um só valor (o mesmo campo duas vezes: o montante, e a sua parte do total), usa-se o handle do valor, mais abaixo.

// Local variables
n_pbt_crosstab_field lnv_field

// O campo montante : a sua etiqueta e uma escala de cores
lnv_field = uo_crosstab.of_field(/*field*/ "amount")
lnv_field.is_label = "Volume de negócios"
lnv_field.is_conditional_formatting = lnv_field.CF_SCALE

⚠️ Alteração incompatível. Esta propriedade chamava-se is_cf: a abreviatura nada dizia no ponto de utilização. O nome antigo já não existe — um código que o utilize não compila. A substituição é mecânica: is_cf → is_conditional_formatting, sem alteração de valores nem de comportamento.

Propriedades de um valor #

of_value (integer ai_position) devolve o handle de um valor da zona Valores, pela sua posição (1 = o primeiro). Um campo pode lá estar duas vezes — o montante, e a sua parte do total geral — e cada valor tem as suas definições, que prevalecem sobre as do seu campo. O handle designa uma posição: após of_remove_value, of_move_value, of_remove_field, of_remove_calc_measure, of_clear_layout ou of_set_layout é libertado — peça of_value de novo. As suas constantes SHOW_* e CF_* são as de n_pbt_crosstab_field.

PropriedadeTipoPredefiniçãoFunção
is_aggstringa de of_add_value_fieldAgregação deste valor: uma constante AGG_* do componente (uo_crosstab.AGG_AVG). Uma medida calculada não tem nenhuma a escolher: a atribuição é ignorada
is_showstring"normal"O que as células deste valor apresentam: SHOW_NORMAL, SHOW_PCT_GRAND, SHOW_PCT_ROW, SHOW_PCT_COL, SHOW_RUNNING, SHOW_DIFF (como no campo)
is_conditional_formattingstring"none"Formatação condicional deste valor: CF_NONE, CF_SCALE, CF_BARS, CF_ICONS
is_formatstringFormat da colunaFormato de apresentação só deste valor, um formato PowerBuilder ("#,##0.00", "$#,##0;($#,##0)"). Vazio = o Format da coluna do DataWindow. Relida: o formato em vigor
ib_negative_redbooleanfalseOs números negativos deste valor a vermelho — no ecrã e na exportação Excel. A mesma definição que a entrada « Negativos a vermelho » do menu do chip
is_labelstring""Etiqueta deste valor nos cabeçalhos (« Parte das vendas »); vazio repõe a de origem, a agregação e a etiqueta do campo (« Soma de Montante »)
MétodoFunção
of_field ( ) → stringO campo que este valor agrega ("amount"); "" quando a posição não contém nenhum valor
// Local variables
n_pbt_crosstab_value lnv_share, lnv_amount

// O montante duas vezes em Valores : a soma, depois a sua parte do total geral
uo_crosstab.of_add_value_field(/*field*/ "amount", /*agg*/ uo_crosstab.AGG_SUM)
uo_crosstab.of_add_value_field(/*field*/ "amount", /*agg*/ uo_crosstab.AGG_SUM)

// So o segundo valor : a sua parte do total geral, com a sua propria etiqueta
lnv_share = uo_crosstab.of_value(/*position*/ 2)
lnv_share.is_show = n_pbt_crosstab_value.SHOW_PCT_GRAND
lnv_share.is_label = "Parte das vendas"

// O primeiro valor : duas casas decimais, os negativos a vermelho
lnv_amount = uo_crosstab.of_value(/*position*/ 1)
lnv_amount.is_format = "#,##0.00"
lnv_amount.ib_negative_red = true

Métodos #

Alimentar e nomear #

MétodoFunção
of_from_datastore (datastore ads)Transmite o conjunto de dados: os campos são deduzidos das colunas do DataStore, a respetiva etiqueta do texto de cabeçalho e o formato predefinido dos seus valores do Format da coluna. Um texto com uma tabulação ou uma quebra de linha fica na sua linha; um valor CHAR perde os espaços de preenchimento; um decimal lê-se com o separador do posto; um valor vazio (NULL, texto vazio) é um único membro (vazio), colocado em último; as etiquetas definidas por is_label sobrevivem ao recarregamento. Devolve 0 depois de carregados os dados, -5 se o DataStore não for válido ou não tiver qualquer coluna, -2 se o componente não estiver criado
of_from_datastore (datawindow adw)O mesmo carregamento a partir de um DataWindow: a tabela cruzada lê as suas linhas através de um DataStore de trabalho que as partilha (ShareData, verificado) — o que o DataWindow mostra, a tabela cruza. Devolve 0, -5 quando adw não é válido, não tem colunas ou não consegue partilhar as suas linhas (of_get_last_error diz qual), -2 quando o componente não está criado
of_from_datastore (datawindowchild adwc)O mesmo carregamento a partir de um DataWindowChild (um DataWindow pendente). Os mesmos valores devolvidos
of_field (string as_field)Devolve o handle de um campo, para o etiquetar ou formatar (ver Propriedades de um campo)
of_value (integer ai_position) → n_pbt_crosstab_valueDevolve o handle de um valor da zona Valores, pela sua posição (1 = o primeiro), para definir a sua agregação, apresentação, formato ou etiqueta (ver Propriedades de um valor)
of_value_count ( ) → longO número de valores da zona Valores (um campo que lá está duas vezes conta duas vezes); 0 quando a zona está vazia ou o componente não está criado

Construir a tabela #

MétodoFunção
of_clear_layout ( )Esvazia as quatro zonas: a tabela volta a ficar vazia, os dados permanecem carregados. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_add_row_field (string as_field)Adiciona um campo à zona Linhas (a ordem das chamadas determina a ordem dos níveis). Um campo já em Valores fica lá: pode estar nos dois (uma contagem distinta por membro). Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm ou para uma medida calculada (só vai para Valores), -2 se o componente não estiver criado
of_add_col_field (string as_field)Adiciona um campo à zona Colunas. Um campo já em Valores fica lá: pode estar nos dois (uma contagem distinta por membro). Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm ou para uma medida calculada (só vai para Valores), -2 se o componente não estiver criado
of_add_value_field (string as_field, string as_agg)Adiciona uma medida à zona Valores, com a respetiva agregação (AGG_*, vazio = AGG_SUM). O campo mantém o seu lugar em Linhas, Colunas ou Filtros. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm ou outra agregação, -2 se o componente não estiver criado
of_add_filter_field (string as_field)Adiciona um campo à zona Filtros, acima da tabela. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm ou para uma medida calculada (só vai para Valores), -2 se o componente não estiver criado
of_remove_field (string as_field)Retira um campo da tabela: de todas as zonas onde está (Linhas, Colunas, Filtros, e cada um dos seus valores), com os seus filtros — como «Remover» a partir da lista de campos. O resto da disposição fica como está, e ue_layout_changed comunica a nova. Devolve 0 depois de aplicado, -4 quando o campo não está em nenhuma zona, -5 para um campo que os dados não contêm
of_remove_value (integer ai_position)Retira um valor da zona Valores, pela sua posição (a 2.ª « Soma de Montante » enquanto a 1.ª fica); com o último valor de um campo que não está em mais nenhum lado partem os seus filtros. Devolve 0 depois de aplicado, -5 para uma posição sem valor, -2 se o componente não estiver criado
of_move_value (integer ai_from, integer ai_to)Desloca um valor da zona Valores de uma posição para outra (1 = o primeiro): as suas definições, os filtros e a ordenação que o nomeiam acompanham-no. Devolve 0 depois de aplicado, -5 para uma posição sem valor, -2 se o componente não estiver criado

As agregações aceites por of_add_value_field são disponibilizadas pelo componente sob a forma de constantes: AGG_SUM (predefinição), AGG_COUNT (o número de valores não vazios, como a Contagem do Excel), AGG_COUNT_ROWS (o número de linhas, vazias incluídas), AGG_DISTINCT_COUNT (contagem de valores distintos, as células vazias são ignoradas como no Excel), AGG_AVG, AGG_MIN, AGG_MAX. Uma soma sem qualquer valor é uma célula vazia, não 0; uma « diferença face ao anterior » em que uma das duas células está vazia também é vazia. As percentagens escrevem-se como a língua de apresentação as escreve (57.9% em inglês, 57,9 % em francês).

Totais e subtotais #

Os totais definem-se através de propriedades, descritas acima: ib_row_grand_total e ib_col_grand_total para os totais gerais, ib_row_subtotals e ib_col_subtotals para os subtotais, is_totals_position para a posição da linha de total geral. O menu Opções da grelha (a roda dentada) oferece os mesmos quatro interruptores, uma entrada por eixo: Linha do total geral, Coluna do total geral, Subtotais das linhas, Subtotais das colunas.

Filtrar #

MétodoFunção
of_set_member_filter (string as_field, string as_values_tab)Mantém apenas os valores listados de um campo. Os valores são separados por tabulações (~t) e escrevem-se como a grelha os guarda (ver por baixo da tabela); uma lista vazia remove o filtro, como of_set_member_order. Um campo que não está em nenhuma zona passa para a zona Filtros, para que o filtro se veja. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, -2 se o componente não estiver criado
of_clear_member_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, -2 se o componente não estiver criado
of_set_value_filter (string as_field, string as_type, double ad_a, double ad_b, integer ai_measure_index)Filtra sobre o total da medida n.º ai_measure_index (a primeira = 1): VALUEFILTER_TOP ou VALUEFILTER_BOTTOM (os ad_a primeiros ou últimos), VALUEFILTER_GT, VALUEFILTER_LT (acima, abaixo de ad_a), VALUEFILTER_BETWEEN (entre ad_a e ad_b). Num campo colocado sob outro da sua zona, a classificação faz-se dentro de cada pai (a melhor cidade de cada região); no primeiro nível, sobre toda a tabela. Os membros empatados com o N-ésimo ficam todos. O campo deve estar em Linhas ou em Colunas. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, outro tipo, um Top ou um Bottom de menos de 1 membro ou uma posição sem medida em Valores, -2 se o componente não estiver criado
of_clear_value_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, -2 se o componente não estiver criado
of_set_label_filter (string as_field, string as_type, double ad_a, double ad_b)Filtro numérico sobre o próprio valor do campo: LABEL_GT, LABEL_LT, LABEL_BETWEEN. Um campo de data recebe dias, através da sobrecarga de texto. O campo deve estar em Linhas ou em Colunas. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, outro tipo ou um campo de data, -2 se o componente não estiver criado
of_set_label_filter (string as_field, string as_type, string as_a, string as_b)Filtro de texto sobre o valor do campo: LABEL_CONTAINS, LABEL_BEGINS, LABEL_ENDS (as_a, sem distinguir maiúsculas e minúsculas; as_b não é usado). Num campo de data: LABEL_BEFORE, LABEL_AFTER (as_a, um dia escrito yyyy-mm-dd) ou LABEL_BETWEEN (as_a e as_b, dias incluídos). Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, um tipo que não convém ao campo (LABEL_CONTAINS numa data, LABEL_BEFORE num texto), um texto vazio ou um dia que não o é, -2 se o componente não estiver criado
of_clear_label_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, -2 se o componente não estiver criado

Os valores que of_set_member_filter e of_set_member_order esperam são os que a grelha guarda, nem sempre os que apresenta: num campo derivado de uma data, um mês escreve-se "01"…"12", um trimestre "1"…"4", um ano "2024"; um membro de data não agrupado escreve-se yyyy-mm-dd. O utilizador, por seu lado, encontra o filtro de etiqueta no menu do chip de qualquer campo — texto, número ou data.

Formatar #

O formato de um valor define-se através de uma propriedade: of_field("amount").is_format = "$#,##0.00" para todos os valores de um campo, of_value(2).is_format para um só (ver Propriedades de um campo e Propriedades de um valor). É um formato de apresentação PowerBuilder, lido pelo motor de máscaras da biblioteca; vazio, o valor recebe o Format da coluna do DataWindow. Os negativos a vermelho: of_value(n).ib_negative_red = true. O separador de milhares dos valores sem formato continua a ser is_thousands, a moeda do menu do chip is_currency_symbol.

MétodoFunção
of_set_member_order (string as_field, string as_values_tab)Ordem de apresentação imposta aos valores de um campo (separados por ~t); uma cadeia vazia repõe a ordem natural. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, -2 se o componente não estiver criado

Datas e campos calculados #

MétodoFunção
of_group_date_field (string as_field, string as_part)Cria um campo derivado de uma coluna date, datetime ou timestamp (uma hora sozinha não tem data para agrupar): DATE_YEAR, DATE_QUARTER ou DATE_MONTH, chamado <coluna>__<parte>. Junta-se à lista dos campos e utiliza-se como os restantes. Devolve 0 depois de aplicado, -5 para um campo que os dados não contêm, outra parte ou um campo que não contém datas (um texto, uma hora), -2 se o componente não estiver criado
of_add_calc_field (string as_name, string as_label, string as_formula)Campo calculado linha a linha ("[amount] * 0.8" = o líquido de cada venda, depois somado como qualquer coluna), utilizável em qualquer zona. Não para um rácio de totais (preço médio): isso é of_add_calc_measure. Devolve 0 depois de criado, -5 para um nome ou uma fórmula vazios, um nome que contém / ou `, um nome já usado por uma coluna ou uma fórmula que não compila — o motivo fica então em of_get_last_error, e ue_calc_field_error é desencadeado —, -2` se o componente não estiver criado
of_remove_calc_field (string as_name)Remove um campo calculado. Devolve 0 depois de aplicado, -5 se nenhum campo calculado tiver este nome, -2 se o componente não estiver criado
of_add_calc_measure (string as_name, string as_label, string as_formula)Medida calculada célula a célula, sobre os totais ("[marge] / [ca]" = taxa de margem global). Coloca-se unicamente na zona Valores. A sua fórmula só cita campos de dados: outra medida calculada é recusada. Os mesmos códigos que of_add_calc_field: 0 depois de criada, -5 (o motivo em of_get_last_error, ue_calc_field_error desencadeado), -2 se o componente não estiver criado
of_remove_calc_measure (string as_name)Remove uma medida calculada. Devolve 0 depois de aplicado, -5 se nenhuma medida calculada tiver este nome, -2 se o componente não estiver criado

Uma fórmula aceita os operadores + - * / ( ), números (12, 0.5, .5, 1e3, sempre com ponto) e campos entre parênteses retos; ^ não é um operador. Uma fórmula inválida desencadeia ue_calc_field_error — nada falha.

Expandir, memorizar, exportar #

MétodoFunção
of_expand_all ( ) · of_collapse_all ( )Expande ou recolhe todos os grupos, de linhas E de colunas. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_expand_to_level (integer ai_level)Expande até um determinado nível (1 = apenas o primeiro nível). Devolve 0 depois de aplicado, -5 abaixo de 1, -2 se o componente não estiver criado
of_get_layout ( ) → stringDevolve o estado completo da tabela — guarde-o tal como está e reproduza-o com of_set_layout
of_set_layout (string as_state_json)Restaura um estado obtido anteriormente (o JSON de of_get_layout ou de ue_layout_changed, tal como está). ue_layout_changed comunica a nova disposição uma vez, nada se for a já apresentada; os handles dos valores são libertados. Devolve 0 depois de aplicado, -5 para um texto vazio ou que não seja JSON, -2 se o componente não estiver criado
of_get_cell_value (string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, ref double ad_value)Lê o valor de uma célula, o que a tabela apresenta (0,8 sob 80,0 %, o acumulado sob um acumulado). A sua linha e a sua coluna são os tuplos que ue_cell_double_clicked fornece — {"region":"Nord","city":"Lille"}, um membro vazio null, {} (ou uma cadeia vazia) para o total — e ai_measure é a posição do valor na zona Valores, a partir de 1. Um tuplo nomeia os campos da sua zona a partir do primeiro: {"region":"Nord"} é o subtotal de Nord. A resposta não depende da apresentação: um ramo recolhido ou subtotais ocultos leem-se na mesma. Devolve 0 com o valor em ad_value (NULL para uma célula sem valor), -4 quando a tabela não tem essa célula (um membro ou um campo que não mostra aí) ou não pode ser lida agora — chamada a partir de um evento que a grelha desencadeou enquanto uma ordem deste script esperava: of_get_last_error di-lo, leia depois do evento —, -5 para um tuplo mal formado ou uma posição sem medida, -2 se o componente não estiver criado
of_get_cell_rows (string as_row_tuple_json, string as_col_tuple_json, ref long al_rows[]) → longAs linhas do DataStore que uma célula agrega (drill-through): al_rows[] recebe os seus números de linha e é devolvido o seu número. A célula endereça-se como em of_get_cell_value, sem medida — as mesmas linhas alimentam todos os valores da célula. Os números são os que as linhas têm agora no DataStore dado a of_from_datastore, mesmo após uma ordenação ou um filtro desse DataStore; só contam as linhas que passam todos os filtros da tabela; no modo de demonstração, as linhas além do limite não são usadas, logo não são devolvidas; uma linha eliminada desde o carregamento é omitida. Recarregue a grelha após um Retrieve. Devolve o número (0 ou mais), -4 quando a tabela não tem essa célula ou não pode ser lida agora (ver of_get_cell_value), -5 para um tuplo mal formado, -2 se o componente não estiver criado
of_export_csv (string as_path)Escreve um ficheiro CSV da vista atual (UTF-8 com BOM, ponto e vírgula); ue_csv_saved confirma. Os números tomam o separador decimal da língua de apresentação (a vírgula em francês, alemão, italiano, espanhol, português); um rótulo que seria lido como uma fórmula (= + - @) é escrito precedido de um apóstrofo. O gémeo de of_export_xlsx. Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_export_xlsx (string as_path)Escreve um ficheiro Excel da tabela tal como é apresentada, formatação incluída (negativos a vermelho incluídos); ue_xlsx_saved confirma — ou recusa com o motivo acima de 16 384 colunas ou 1 048 576 linhas, os limites de uma folha Excel. Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado

Comuns #

MétodoFunção
of_reset ( )Repõe o componente no seu estado inicial. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_set_redraw (boolean)Agrupa uma série de modificações numa única representação. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_save_as_png (string) · of_save_as_jpg (string)Exporta a representação como imagem. Devolve 0, -2 se o componente não estiver criado, -4 se a captura falhar, -5 num caminho vazio

Eventos #

EventoAcionado quando
ue_layout_changed (string as_layout_json)A disposição mudou — pelo utilizador (deslocar um campo, mudar uma agregação, ordenar uma coluna, recolher um grupo…) ou pelo código: qualquer ordem que mude o que of_get_layout devolve (of_set_layout incluído) desencadeia-o uma vez, e uma só vez no fim de uma construção enquadrada por of_set_redraw(false) … of_set_redraw(true); nunca quando nada muda, nem com of_reset. as_layout_json é tudo o que of_get_layout guarda
ue_cell_double_clicked (string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, double ad_value)Duplo clique numa célula: os dois primeiros argumentos descrevem o cruzamento ({"region":"Nord","city":"Lille"}, um membro vazio vale null, {} para o total), ai_measure a posição do valor clicado na zona Valores, a partir de 1, e ad_value o valor que a célula apresenta — 0.8 sob « 80,0 % », o acumulado sob um acumulado — ou NULL para uma célula vazia. Os dois tuplos e ai_measure formam o endereço que of_get_cell_value volta a ler. É o ponto de entrada de um detalhe
ue_csv_saved (string as_path, boolean ab_ok, string as_error)O ficheiro CSV foi escrito — ou não, e as_error diz porquê
ue_xlsx_saved (string as_path, boolean ab_ok, string as_error)O ficheiro Excel foi escrito — ou não, e as_error indica porquê
ue_calc_field_error (string as_field, string as_message)Uma fórmula de campo ou de medida calculada é inválida
ue_copy (string as_tsv)O utilizador copiou uma seleção de células (Ctrl+C): a grelha já colocou o texto na área de transferência, o evento devolve-lhe o mesmo texto — para o registar ou reutilizar noutro lado. as_tsv é um texto separado por tabulações que traz por defeito os cabeçalhos — os nomes das colunas numa primeira linha, o membro de cada linha (o seu caminho completo, « Nord / Lille ») numa primeira coluna — ou só os valores com ib_copy_headers = false. No modo de demonstração a cópia é uma exportação: recusada, e a grelha di-lo
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 tabela é viva: é esse todo o interesse do componente. Com o painel de campos visível (ib_field_list = true), o utilizador pode:

Cada uma destas manipulações, exceto a cópia (que desencadeia ue_copy), é comunicada em ue_layout_changed: em conjunto com of_get_layout / of_set_layout, permite oferecer «vistas guardadas» aos utilizadores.

Com o teclado. A construção da tabela faz-se sem rato — chips, menus, dobragem e ordenação: Tab leva a um campo, a um triângulo de dobragem ou a um cabeçalho ordenável, Enter ou Espaço aciona-o. Num campo abre o respetivo menu — aquele que tem Adicionar às linhas / às colunas / aos valores / aos filtros e Remover: toda a construção da tabela passa por aí. Shift+F10 ou a tecla Menu também abrem esse menu, e o foco segue o campo acabado de mover, mesmo para outra zona. Selecionar células e copiá-las (Ctrl+C) exige hoje o rato.


Exemplos #

Um relatório de vendas completo #

// Linhas: regiao e depois cidade dentro de cada regiao
uo_crosstab.of_clear_layout()
uo_crosstab.of_add_row_field(/*field*/ "region")
uo_crosstab.of_add_row_field(/*field*/ "city")

// Colunas: uma por ano
uo_crosstab.of_add_col_field(/*field*/ "year")

// Celulas: o montante total
uo_crosstab.of_add_value_field(/*field*/ "amount", /*agg*/ uo_crosstab.AGG_SUM)

// Apresentacao: montantes legiveis, subtotais e totais gerais
uo_crosstab.of_field(/*field*/ "amount").is_format = "$#,##0"
uo_crosstab.ib_row_subtotals = true
uo_crosstab.ib_row_grand_total = true
uo_crosstab.ib_col_grand_total = true

// Colorir as celulas para identificar os grandes montantes num relance
uo_crosstab.of_field(/*field*/ "amount").is_conditional_formatting = n_pbt_crosstab_field.CF_SCALE

Etiquetas legíveis #

As colunas chamam-se muitas vezes mt_ht ou cd_reg. Devem ser renomeadas de uma vez por todas, logo a seguir a of_from_datastore.

// Primeiro os dados : os campos tomam o nome das colunas
uo_crosstab.of_from_datastore(/*ads*/ lds)

// Depois uma etiqueta legivel para cada campo
uo_crosstab.of_field(/*field*/ "region").is_label    = "Região"
uo_crosstab.of_field(/*field*/ "city").is_label     = "Cidade"
uo_crosstab.of_field(/*field*/ "category").is_label = "Categoria"
uo_crosstab.of_field(/*field*/ "year").is_label     = "Ano"
uo_crosstab.of_field(/*field*/ "amount").is_label   = "Volume de negócios"
uo_crosstab.of_field(/*field*/ "quantity").is_label  = "Quantidade"

Analisar proporções em vez de montantes #

// Local variables
n_pbt_crosstab_field lnv_amount

// Partir de zonas vazias e depois colocar os campos
uo_crosstab.of_clear_layout()
uo_crosstab.of_add_row_field(/*field*/ "category")
uo_crosstab.of_add_col_field(/*field*/ "year")
uo_crosstab.of_add_value_field(/*field*/ "amount", /*agg*/ uo_crosstab.AGG_SUM)

// Manter apenas duas categorias no ecra (valores separados por uma tabulacao)
uo_crosstab.of_set_member_filter(/*field*/ "category", /*values_tab*/ "Informatique~tMobilier")

// O campo montante, para definir como e apresentado
lnv_amount = uo_crosstab.of_field(/*field*/ "amount")

// Mostrar a proporcao de cada celula no total da sua coluna
lnv_amount.is_show = lnv_amount.SHOW_PCT_COL

// Uma pequena barra em cada celula para comparar as proporcoes num relance
lnv_amount.is_conditional_formatting = lnv_amount.CF_BARS

Uma medida à medida: o preço médio #

Uma medida calculada é avaliada sobre os totais de cada célula, e não linha a linha: é isso que torna um rácio correto.

// Partir de zonas vazias e depois colocar os campos
uo_crosstab.of_clear_layout()
uo_crosstab.of_add_row_field(/*field*/ "region")

// Os dois totais que vao servir de base ao calculo
uo_crosstab.of_add_value_field(/*field*/ "amount",  /*agg*/ uo_crosstab.AGG_SUM)
uo_crosstab.of_add_value_field(/*field*/ "quantity", /*agg*/ uo_crosstab.AGG_SUM)

// Preco medio = montante total dividido pela quantidade total
uo_crosstab.of_add_calc_measure(/*name*/ "avg_price", /*label*/ "Preço médio", /*formula*/ "[amount] / [quantity]")
uo_crosstab.of_field(/*field*/ "avg_price").is_format = "$#,##0.00"

// Depois coloca-la entre os valores como qualquer campo (o agregado nao conta: uma medida calcula-se)
uo_crosstab.of_add_value_field(/*field*/ "avg_price", /*agg*/ uo_crosstab.AGG_SUM)
// event ue_calc_field_error de uo_crosstab : (string as_field, string as_message)
// Formula invalida: avisar sem nada quebrar, a tabela permanece visivel.
uo_status.of_panel(/*key*/ "main").is_text = "Fórmula " + as_field + " : " + as_message

Analisar por mês, trimestre ou ano #

Uma coluna de data não se cruza tal como está — cada dia daria origem à sua própria linha. É necessário derivar primeiro o nível pretendido.

// Criar tres campos derivados da coluna sale_date
uo_crosstab.of_group_date_field(/*field*/ "sale_date", /*part*/ uo_crosstab.DATE_YEAR)
uo_crosstab.of_group_date_field(/*field*/ "sale_date", /*part*/ uo_crosstab.DATE_QUARTER)
uo_crosstab.of_group_date_field(/*field*/ "sale_date", /*part*/ uo_crosstab.DATE_MONTH)

// Depois cruza-los como qualquer outro campo: ano em colunas, trimestre por baixo
uo_crosstab.of_add_col_field(/*field*/ "sale_date__year")
uo_crosstab.of_add_col_field(/*field*/ "sale_date__quarter")

O ranking das dez melhores regiões #

// Manter apenas as 10 regioes com maior total na primeira medida
uo_crosstab.of_set_value_filter(/*field*/ "region", /*type*/ uo_crosstab.VALUEFILTER_TOP, /*a*/ 10, /*b*/ 0, /*measure_index*/ 1)

Num campo colocado sob outro, a classificação faz-se dentro de cada pai: a melhor cidade de cada região, não a melhor cidade do país. Os empates ficam todos.

// As cidades sob as regioes
uo_crosstab.of_add_row_field(/*field*/ "region")
uo_crosstab.of_add_row_field(/*field*/ "city")

// A melhor cidade de cada regiao, na primeira medida
uo_crosstab.of_set_value_filter(/*field*/ "city", /*type*/ uo_crosstab.VALUEFILTER_TOP, /*a*/ 1, /*b*/ 0, /*measure_index*/ 1)

Exportar #

A exportação reproduz exatamente a vista em curso: os mesmos filtros, os mesmos totais, a mesma formatação.

// Para Excel: o ficheiro e escrito diretamente no caminho indicado
uo_crosstab.of_export_xlsx(/*path*/ "C:\temp\ventes.xlsx")
// event ue_xlsx_saved de uo_crosstab : (string as_path, boolean ab_ok, string as_error)
// inv_notif = um n_pbt_toaster declarado como variavel de instancia da window
if ab_ok then
    inv_notif.is_title = "Exportação concluída"
    inv_notif.is_text  = as_path
    inv_notif.is_kind  = inv_notif.KIND_SUCCESS
else
    inv_notif.is_title = "Exportação impossível"
    inv_notif.is_text  = as_error
    inv_notif.is_kind  = inv_notif.KIND_ERROR
end if
inv_notif.of_show()
// Para CSV: um ficheiro, como para o Excel; ue_csv_saved confirma
uo_crosstab.of_export_csv(/*path*/ "C:\exports\ventes.csv")

Oferecer vistas guardadas #

// Local variables
string ls_view

// Guardar a vista atual : of_get_layout responde de imediato
ls_view = uo_crosstab.of_get_layout()

// Guardar o conteudo TAL COMO ESTA : reproduz-se sem transformacao.
of_save_view(is_current_view, ls_view)
// Mais tarde: repor uma vista guardada
uo_crosstab.of_set_layout(/*state_json*/ of_read_view("Ventes par region"))

Descer ao detalhe por trás de um número #

// event ue_cell_double_clicked de uo_crosstab : (string as_row_tuple_json, string as_col_tuple_json, integer ai_measure, double ad_value)
// Local variables
long ll_rows[], ll_count, ll_i

// As linhas do DataStore por tras do numero com duplo clique
ll_count = uo_crosstab.of_get_cell_rows(/*row_tuple_json*/ as_row_tuple_json, /*col_tuple_json*/ as_col_tuple_json, /*rows*/ ll_rows)

// Nada a mostrar : nenhuma linha, ou uma celula que nao pode ser lida agora
if ll_count <= 0 then return

// Copia-las para a lista de detalhe : ids_sales e o DataStore dado a of_from_datastore
dw_detail.Reset()
for ll_i = 1 to ll_count
	ids_sales.RowsCopy(ll_rows[ll_i], ll_rows[ll_i], Primary!, dw_detail, dw_detail.RowCount() + 1, Primary!)
next

Os dois tuplos e ai_measure formam o endereço da célula: of_get_cell_value volta a lê-lo mais tarde, tal como a tabela o apresenta nesse momento.

// ue_cell_double_clicked event of uo_crosstab : the address of the cell, read again later
// Local variables
double ld_value

// Read the cell again from its address : 0 when it exists
if uo_crosstab.of_get_cell_value(/*row_tuple_json*/ as_row_tuple_json, /*col_tuple_json*/ as_col_tuple_json, /*measure*/ ai_measure, /*value*/ ld_value) = 0 then

	// ld_value is what the cell shows ; NULL for an empty cell
end if

Uma célula também se lê sem clique, pelos seus membros: um tuplo parcial designa um subtotal. E of_remove_field retira um campo de todas as suas zonas de uma só vez, filtros incluídos.

// The sales of Nord in 2025, first measure of Values
// Local variables
double ld_north

// A partial address : the region and the year, no other member
uo_crosstab.of_get_cell_value(/*row_tuple_json*/ '{"region":"Nord"}', /*col_tuple_json*/ '{"year":"2025"}', /*measure*/ 1, /*value*/ ld_north)

// Take the year out of the table, filters included
uo_crosstab.of_remove_field(/*field*/ "year")

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_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
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

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