PBToolboxAI v3 ← 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 items— (os campos são colocados através de métodos)
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; exportações CSV e Excel 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
datastore lds
lds = create datastore
lds.dataobject = "d_ventes"
lds.SetTransObject(SQLCA)
lds.Retrieve()

// 1. Transmitir os dados: os campos sao deduzidos das colunas
uo_croise.of_set_data(lds)

// 2. Distribuir os campos pelas zonas
uo_croise.of_add_row_field(/*campo*/ "region")
uo_croise.of_add_col_field(/*campo*/ "annee")
uo_croise.of_add_value_field(/*campo*/ "montant", /*agregado*/ uo_croise.AGG_SUM)

// 3. Apresentar: formato dos montantes e totais gerais
uo_croise.of_set_value_format(/*campo*/ "montant", /*decimais*/ 0, /*milhares*/ "locale", /*simbolo*/ "$", /*simbolo_antes*/ true)
uo_croise.ib_row_grand_total = true
uo_croise.ib_col_grand_total = true
// event ue_cell_double_clicked de uo_croise : (string as_row_tuple_json, string as_col_tuple_json, double ad_value)
// O utilizador quer o detalhe por tras de um numero: abrir a lista correspondente.
of_ouvrir_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
AGG_SUM · AGG_COUNT · AGG_DISTINCT_COUNT"sum" "count" "dcount"of_add_value_field
AGG_AVG · AGG_MIN · AGG_MAX"avg" "min" "max"of_add_value_field

As constantes de agregação leem-se no componente: uo_croise.AGG_SUM. As de um campo (SHOW_*, CF_*) leem-se no handle do campo.


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)
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)
ib_field_listbooleantrueMostra o painel de campos, onde o utilizador reorganiza a tabela com o rato
ib_row_subtotalsbooleantrueMostra um subtotal por grupo de linhas
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)
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_stylestringfluentEstilo visual do componente (constantes THEME_STYLE_*)
is_theme_modestringlightVariante clara ou escura (constantes THEME_MODE_*)
il_theme_accentlong-1Cor de destaque deste componente (-1 = destaque 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_labelstring""Etiqueta legível do campo ("montant" → "Volume de negócios")
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) ou CF_BARS (barras na célula)

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…).

n_pbt_crosstab_field lnv_champ

lnv_champ = uo_croise.of_field(/*campo*/ "montant")
lnv_champ.is_label = "Volume de negócios"
lnv_champ.is_conditional_formatting = lnv_champ.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.


Métodos #

Alimentar e nomear #

MétodoFunção
of_set_data (datastore ads_data)Transmite o conjunto de dados: os campos são deduzidos das colunas do DataStore e a respetiva etiqueta do texto de cabeçalho. 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_field (string as_field)Devolve o handle de um campo, para o etiquetar ou formatar (ver Propriedades de um campo)

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). Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_add_col_field (string as_field)Adiciona um campo à zona Colunas. Devolve 0 depois de aplicado, -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. Devolve 0 depois de aplicado, -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, -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, AGG_DISTINCT_COUNT (contagem de valores distintos), AGG_AVG, AGG_MIN, AGG_MAX.

Totais e subtotais #

MétodoFunção

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). Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_clear_member_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -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: "top" (os ad_a primeiros), "gt", "lt", "between". ai_measure_index designa a medida em causa (a primeira = 1). Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_clear_value_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
of_set_label_filter (string as_field, string as_type, double ad_a, double ad_b)Filtra sobre o próprio valor do campo: "gt", "lt", "between". Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_clear_label_filter (string as_field)Remove este filtro. Devolve 0 depois de aplicado, -2 se o componente não estiver criado

Formatar #

MétodoFunção
of_set_value_format (string as_field, integer ai_decimals, string as_thousands, string as_suffix { , boolean ab_symbol_before })Formato de uma medida: número de casas decimais (0 a 6), separador de milhares ("locale", "space", "none"), símbolo — após o número por defeito (1 234 EUR), ANTES quando ab_symbol_before é true ($1,234). Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_clear_value_format (string as_field)Regresso ao formato predefinido. Devolve 0 depois de aplicado, -2 se o componente não estiver criado
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 num argumento inválido, -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 de data: "year", "quarter" ou "month". Junta-se à lista dos campos e utiliza-se como os restantes. Devolve 0 depois de aplicado, -5 num argumento inválido, -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 ("[montant] * 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 aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_remove_calc_field (string as_name)Remove um campo calculado. Devolve 0 depois de aplicado, -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. Devolve 0 depois de aplicado, -5 num argumento inválido, -2 se o componente não estiver criado
of_remove_calc_measure (string as_name)Remove uma medida calculada. Devolve 0 depois de aplicado, -2 se o componente não estiver criado

Uma fórmula aceita os operadores + - * / ( ), números e campos entre parênteses retos. 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. 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, -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. Devolve 0 depois de aplicado, -5 num argumento inválido, -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. 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, formatação incluída; ue_xlsx_saved confirma. 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)O utilizador reorganizou a tabela (deslocou um campo, alterou uma agregação, recolheu um grupo…)
ue_cell_double_clicked (string as_row_tuple_json, string as_col_tuple_json, double ad_value)Duplo clique numa célula: os dois primeiros argumentos descrevem o cruzamento, o terceiro o valor apresentado. É 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): cabe ao programador colocá-la na área de transferência
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 é comunicada em ue_layout_changed: em conjunto com of_get_layout / of_set_layout, permite oferecer «vistas guardadas» aos utilizadores.

Com o teclado. Cada um destes gestos é alcançável sem rato: 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í.


Exemplos #

Um relatório de vendas completo #

// Linhas: regiao e depois cidade dentro de cada regiao
uo_croise.of_clear_layout()
uo_croise.of_add_row_field(/*campo*/ "region")
uo_croise.of_add_row_field(/*campo*/ "ville")

// Colunas: uma por ano
uo_croise.of_add_col_field(/*campo*/ "annee")

// Celulas: o montante total
uo_croise.of_add_value_field(/*campo*/ "montant", /*agregado*/ uo_croise.AGG_SUM)

// Apresentacao: montantes legiveis, subtotais e totais gerais
uo_croise.of_set_value_format(/*campo*/ "montant", /*decimais*/ 0, /*milhares*/ "locale", /*simbolo*/ "$", /*simbolo_antes*/ true)
uo_croise.ib_row_subtotals = true
uo_croise.ib_row_grand_total = true
uo_croise.ib_col_grand_total = true

// Colorir as celulas para identificar os grandes montantes num relance
uo_croise.of_field(/*campo*/ "montant").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_set_data.

uo_croise.of_set_data(lds)

uo_croise.of_field("region").is_label    = "Região"
uo_croise.of_field("ville").is_label     = "Cidade"
uo_croise.of_field("categorie").is_label = "Categoria"
uo_croise.of_field("annee").is_label     = "Ano"
uo_croise.of_field("montant").is_label   = "Volume de negócios"
uo_croise.of_field("quantite").is_label  = "Quantidade"

Analisar proporções em vez de montantes #

n_pbt_crosstab_field lnv_montant

uo_croise.of_clear_layout()
uo_croise.of_add_row_field(/*campo*/ "categorie")
uo_croise.of_add_col_field(/*campo*/ "annee")
uo_croise.of_add_value_field(/*campo*/ "montant", /*agregado*/ uo_croise.AGG_SUM)

// Manter apenas duas categorias no ecra (valores separados por uma tabulacao)
uo_croise.of_set_member_filter(/*campo*/ "categorie", /*valores*/ "Informatique~tMobilier")

lnv_montant = uo_croise.of_field(/*campo*/ "montant")

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

// Uma pequena barra em cada celula para comparar as proporcoes num relance
lnv_montant.is_conditional_formatting = lnv_montant.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.

uo_croise.of_clear_layout()
uo_croise.of_add_row_field(/*campo*/ "region")

// Os dois totais que vao servir de base ao calculo
uo_croise.of_add_value_field(/*campo*/ "montant",  /*agregado*/ uo_croise.AGG_SUM)
uo_croise.of_add_value_field(/*campo*/ "quantite", /*agregado*/ uo_croise.AGG_SUM)

// Preco medio = montante total dividido pela quantidade total
uo_croise.of_add_calc_measure(/*nome*/ "prix_moyen", /*etiqueta*/ "Preço médio", &
                              /*formula*/ "[montant] / [quantite]")
uo_croise.of_set_value_format(/*campo*/ "prix_moyen", /*decimais*/ 2, /*milhares*/ "locale", /*simbolo*/ "$", /*simbolo_antes*/ true)

// Depois coloca-la entre os valores como qualquer campo (o agregado nao conta: uma medida calcula-se)
uo_croise.of_add_value_field(/*campo*/ "prix_moyen", /*agregado*/ uo_croise.AGG_SUM)
// event ue_calc_field_error de uo_croise : (string as_field, string as_message)
// Formula invalida: avisar sem nada quebrar, a tabela permanece visivel.
uo_statut.of_item("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 date_vente
uo_croise.of_group_date_field(/*campo*/ "date_vente", /*nivel*/ "year")
uo_croise.of_group_date_field(/*campo*/ "date_vente", /*nivel*/ "quarter")
uo_croise.of_group_date_field(/*campo*/ "date_vente", /*nivel*/ "month")

// Depois cruza-los como qualquer outro campo: ano em colunas, trimestre por baixo
uo_croise.of_add_col_field("date_vente__year")
uo_croise.of_add_col_field("date_vente__quarter")

O ranking das dez melhores regiões #

// Manter apenas as 10 regioes com maior total na primeira medida
uo_croise.of_set_value_filter(/*campo*/ "region", /*tipo*/ "top", &
                              /*a*/ 10, /*b*/ 0, /*medida*/ 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_croise.of_export_xlsx("C:\temp\ventes.xlsx")
// event ue_xlsx_saved de uo_croise : (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_croise.of_export_csv(/*caminho*/ "C:\exports\ventes.csv")

Oferecer vistas guardadas #

string ls_vue

// Guardar a vista atual : of_get_layout responde de imediato
ls_vue = uo_croise.of_get_layout()

// Guardar o conteudo TAL COMO ESTA : reproduz-se sem transformacao.
of_enregistrer_vue(is_vue_courante, ls_vue)
// Mais tarde: repor uma vista guardada
uo_croise.of_set_layout(of_lire_vue("Ventes par region"))

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

// event ue_cell_double_clicked de uo_croise : (string as_row_tuple_json, string as_col_tuple_json, double ad_value)
// Os dois primeiros argumentos descrevem o cruzamento (que valores de linhas,
// que valores de colunas): o suficiente para reconstruir uma consulta de detalhe.
w_detail_ventes lw_detail

OpenWithParm(lw_detail, as_row_tuple_json + "|" + as_col_tuple_json)

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