O documento descreve os elementos e funcionalidades de uma web panel em GeneXus. As web panels permitem:
1) Exibir dados através de um formulário web com variáveis, atributos e controles;
2) Definir regras, condições, subrotinas e eventos para interação do usuário;
3) Carregar dados de tabelas relacionadas automaticamente.
2. Os elementos das web panels são:
Web Form: Cada web panel contem um form Web, o qual deve ser desenhado pelo analista agregando
variáveis, atributos, assim como outros controles, para que o usuário possa interagir com o mesmo.
Regras: As regras de uma web panel permitem definir certos comportamentos pontuais de dito objeto. Por
exemplo, declarar quais parâmetros recebe, definir quais va is não queremos que sejam aceitas no form
mas utilizadas para mostrar informação, etc.
Condições: É para definir as condições que devem cumprir os dados a ser recuperados (filtros).
Subrotinas: São rotinas locais na web panel.
Eventos: As web panels empregam a programação orientada a eventos. Este tipo de programação permite
definir c digo ocioso, que se ativa em resposta a certas ações provocadas pelo usuário ou pelo sistema. Nesta
seção de uma web panel é onde se define o c digo ocioso associado aos eventos que podem ocorrer durante
a execução da web panel.
Propriedades: São caracter sticas a serem configuradas para definir certos detalhes referentes ao
comportamento geral da web panel.
Ajuda: Permite a inclusão de texto de ajuda, que os usuários podem consultar em tempo de execução da web
panel.
Documentação: Permite a inclusão de texto t cnico como documentação para os desenvolvedores.
3. No exemplo, a web panel contem duas variáveis &StartDate e &EndDate como se mostra acima. Em tempo de
execução, o usuário pode ingressar valores nas variáveis &StartDate e &EndDate visto que nas web panels as
variáveis por default são de entrada.
No evento Enter da web panel (associado ao botão Billing Generation), se obtêm e gravam as faturas cujas
datas se encontrem na faixa especificada.
De modo que a definição desta web panel é para que o usuário ingresse a faixa de datas, e ao selecionar o
botão Billing Generation, se execute o processamento das faturas.
4. A web panel mostrada acima foi criada para exibir os dados de um cliente. Precisa ser chamada a partir de outro objeto,
passando por parâmetro o código do cliente do qual se quer mostrar a informação.
Uma web panel é um objeto tipicamente utilizado para mostrar informação. Então, quando GeneXus encontra atributos no
form, qual intenção do programador ao ter colocado isso? Pois, o que está pedindo implicitamente é que se busque os
dados correspondentes a base de dados para mostrá-los.
Com a web panel anterior, GeneXus vai a tabela CUSTOMER e filtra pelo atributo recebido por parâmetro, CustomerId,
mostrará a informação do registro encontrado. Que informação? A que reside nos atributos que figuram no form. Mas o
atributo CountryName não se encontra na tabela CUSTOMER. Pois acontece o mesmo que com um for each, um grupo de
grupo de Data Providers, etc., isto é, desde o registro da tabela base, se acessa o registro relacionado da tabela estendida
necessária, para obter o valor do atributo requerido (em nosso caso acessa a tabela COUNTRY para recuperar o valor de
CountryName).
As inferências que GeneXus realiza são as seguintes:
Ao se tratar de uma web panel, os atributos que figurem serão de consulta1. Então GeneXus deve acessar a base de dados
para recuperar seus valores. De quais tabelas? Vai depender se a Web panel possui grids ou não:
• Web panel plana (sem grid): os atributos estão “soltos” no form, como no caso que estamos mostrando. Se isso acontece,
é porque o analista necessita acessar a informação de um registro de uma tabela (e eventualmente dos registros
relacionados pela tabela estendida), como é o caso do exemplo. Neste caso, a web panel estará bem programada se além
disso se agregar um filtro que determine “esse” registro a ser mostrado. Em nosso caso, temos a regra parm que ao receber
no atributo PK da tabela somente vai recuperar um registro. GeneXus determina uma tabela base da web panel, assim
como faz para um for each. Como? Buscando a mínima tabela estendida que contenha os atributos..
• Web panel com um ou mais grids: veremos em seguida, mas já podemos pensar... Qual o sentido de colocar um grid?
Mostrar informação repetitiva. No caso geral: cada grid mostra muitos registros de uma tabela (e sua informação associada).
____________________________________________________________________________________________1 Ao contrário do que acontece com os atributos nas transações (exceto os inferidos ou os que tem regra noaccept ou propriedade Enabled
desabilitada).
5. O que diferencia está web panel da anterior é que ela não é plana.
Quando se incluiu um grid num form, se está indicando que vai mostrar uma quantidade indefinida de dados
(neste caso, clientes).
Visto que nesta web panel tem envolvidos atributos, GeneXus infere que deseja acessar a base de dados.
Simplesmente dizendo quais atributos deseja mostrar, sem necessidade de mais informação. Existe um grid,
tem atributos, então, necessariamente terá tabela base, isto é, a tabela da base de dados navegada em busca
da informação requerida.
Se ao invés de mostra esta informação em tela, quisermos uma listagem, vamos criar um procedimento com
um print block ‘customer’ com os atributos CustomerName e CountryName e no source programaríamos:
for each
print customer
endfor
Isto é a análogo, somente que o for each está implícito, não tem que especificá-lo. Cada linha do grid que se
carrega, é como o print que se executa em cada iteração do for each da listagem.
Das tabelas CUSTOMER e COUNTRY e da relação entre ambas é Na1, GeneXus determina a tabela base
desta web panel (sendo que a tabela base seja a mínima que contenha todos os atributos referidos). Observe
que este exemplo difere do anterior, que os atributos aparecem num grid, e portanto, não precisa ser realizado
o filtro, fica somente registros de CUSTOMER. Nesta web panel não tem a regra parm que estabeleça filtro
algum.
Também vamos ver que conseguimos que esta web panel além de mostrar os clientes da base de dados no
grid, podem realizar filtros para os clientes que se quer ver em cada oportunidade, seja por nome do cliente,
endereço ou por ambos. Por isso as variáveis aparecem no form.
6. 335
Quando GeneXus pode determinar automaticamente uma tabela para carregar as linhas do grid, o faz, e nesse
caso não precisa dessa informação. É por isso que falamos que nesse caso tem um for each ‘implícito’. Depois
veremos casos em que isso não acontece (grids sem tabela base).
Observe o exemplo, existindo 4 registros na tabela, são carregados um de cada vez, um a um dos quatro.
Se agora queremos que o usuário possa filtrar os clientes que deseja ver...entra em questão as variáveis que
definimos na parte fixa do form, como veremos na página seguinte.
7. 336
Observe como na janela de propriedade do control Grid, aparece un de nome ‘Conditions’. Clicando no combo
abre um editor para especificar as condições booleanas que devem cumprir os registros para ser carregados
como linhas do grid.
É por essa razão que foi agregado as variáveis &CustomerName e &CountryName no form da web panel, para
que o usuário possa ingressar ali valores que operem como filtros sobre os dados a mostrar. Em nosso caso,
estabelecemos filtros com o operador like. As variáveis na parte plana do form de web panels são por default
de entrada. Depois veremos que se estiverem em grids são por default de saída.
Observe que as condições (separadas com “;”) equivalem as que apareciam nas cláusulas where de um for
each (ou grupo repetitivo de data provider).
Da mesma maneira, por questões de otimização, pode determinar, igual se fazia com um for each, critério de
ordenação da tabela percorrida, como se mostra acima no exemplo.
Nota: Assim mesmo, da mesma forma que num procedimento, as condições locais podem ser realizadas no
grid (for each), mas também podem ser gerais, mediante o selector Conditions. Isto tem sentido quando tiver
mais de um grid (for each), para não ter que repetir cada vez a mesma condição.
8. 337
A propriedade Automatic Refresh que se encontra a nível da Web Panel pode ter os seguintes valores:
• When variables in conditions change (valor por default): depois de chamar automaticamente o refresh, se dispara o
evento Load carregando o grid segundo os novos valores das variáveis.
• No
Dependendo do tipo de dados do filtro, e do control web utilizado para filtrar, a condição será aplicada quando se está
digitando ou ao abandonar o campo.
No caso de filtros em controles edit, para tipo de dados Character, são aplicados quando o usuário vai digitando. Para tipo
de dados Date, DateTime e Numeric, as condições são avaliadas ao sair do campo.
No caso de filtros combo boxes ou dynamic combos, as condições são avaliadas quando se abandona o campo. Para
Check boxes e Radio buttons, as condições são avaliadas quando o valor é alterado.
Execução: o que acontece no cliente e no servidor ao ter a propriedade por default e um grid com tabela base?
1ª execução (variáveis vazias):
For each CUSTOMER
guardar em memória CustomerName
acessar o registro de COUNTRY relacionado
guardar em memória CountryName
carregar (load) linha no grid com ambos valores
N-ésima execução (altera o valor da variável das conditions):
Automaticamente no browser do cliente se detecta a mudança refresh no servidor para voltar a carregar o grid com os
registros que cumpram as condições (com os novos valores das variáveis) load para cada linha.
Conclusão: Existem dois eventos do sistema que ocorrem no momento da carga do form (Refresh) e da carga de cada
linha do grid (Load). Como veremos, estes eventos podem ter códigos associados para serem executados nos momentos
específicos...
9. 338
Ampliaremos a funcionalidade de nossa web panel, permitindo ver o estado de cada cliente, e para aqueles
que estiverem ‘On Hold’, brindando a possibilidade de os passar para o estado ‘Active’.
Para fazer isto, agregaremos ao grid o atributo CustomerStatus que mostra o estado, e uma variável booleana
&Select, que permitirá ao usuário selecionar aqueles clientes que deseja ‘ativar’. Além disso um botão para
efetivamente ativar todos os clientes marcados. Mas isto o faremos num segundo momento.
Observe que se o tipo de dados da variável &select booleano, por default aparece no grid como um check box.
Para assegurar que o usuário somente tente ‘ativar’ clientes ‘On Hold’, desejamos que somente apareça
habilitado este check box quando corresponde... para ele necessitaremos programar a carga de cada linha, isto
é, o evento Load...
10. 339
Na seção Events da web panel, programamos o evento Load do grid que vemos acima. No exemplo,
customerGrid é o nome que demos ao control grid no form.
Ao se tratar de uma web panel com um único grid, também poderíamos ter programado o evento Load:
Event Load
if CustomerStatus = Status.OnHold
&select.Enabled = 1
else
&select.Enabled = 0
endif
endevent
Isto é, no caso de uma web panel com um único grid, não é necessário qualificar o evento com o nome do grid.
Igualmente recomendamos fazer, antecipando a possibilidade futura de agregar outro grid no form da web
panel.
O evento Load é disparado para cada linha que vai carregar no grid, encontrando este comando ou não. O que
fazemos no exemplo é aproveitar este momento imediatamente anterior a carga, para efetuar uma ação. E
esse é o código que incluímos no evento.
Agora sim, estamos em condições de implementar a ‘activate’, para isso precisamos associar ao botão um
evento, que poderá ser o evento Enter ou um de usuário...
11. 340
No exemplo, quando o usuário pressiona o botão ‘Confirm’, necessitamos percorrer todas as linhas do grid, e
para cada uma delas, se o usuário marcou a variável boleana &Select f (check box), devemos alterar o estado
do cliente correspondetne, de ‘On Hold’ a ‘Active’.
Ao inserir o botão no form da web panel, e editar suas propriedades, por default se pode observar que o botao
esta associado ao evento Enter (ver propiedad OnClickEvent).
O Entrr será um evento do sistema, executado quando o usuário faz clique no controle associado, assim como
quando ele pressiona a tecla Enter.
Neste exemplo veremos na 1a vez:
• Possibilidade de definir eventos de usuário e associar os controles ou utilizar o evento Enter do sistema.
• Comando For each line, para percorrer as linhas já carregadas no grid.
• Variáveis num grid passam a ser Read only (de saída) por default, a serem de entrada, quando é utilizado um
comando for each line nesse grid (também quando é programado os eventos OnClickEvent, Click, etc., em
alguma coluna do grid).
Observe que a única coisa em comum no comando For each line e comando For each estudado antes, o fato
de representar um estrutura repetitiva. A diferença mais importante: enquanto o for each percorre registros de
uma tabela (base) da base de dados, o for each line percorre as linhas de um grid.
Em nosso exemplo definimos uma variável &customer, Business Component Customer, trocaremos o estado
para ‘Active’ de todas as linhas do grid que o usuário marcou. Para isso utilizamos o comando for each line
para percorremos o grid.
12. 341
Outra possibilidade, ao invés de utilizar o evento do sistema Enter, é definir um evento de usuário. Isso é
realizado seguindo os passos que estão acima.
Como podemos ver, a maioria dos controles presentes em um form tem a propriedade OnClickEvent
associada. Essa propriedade permite especificar um evento a ser disparado quando o usuário faz clique sobre
o controle. Poderá ser um evento do sistema (Refresh, Enter) ou um evento definido pelo usuário.
13. 342
A parte fixa da web panel por default é de entrada, como já vimos anteriormente para as variáveis utilizadas
para filtrar os clientes (customers) mostrados no grid.
Como mostrar dados no grid
Por default todo atributo e variável que está dentro de um grid se mostra em execução como texto, porque é
unicamente de leitura e por consequencia não pode ser alterado.
Como aceitar dados em um grid
É possível aceitar dados nas variáveis de um grid dependendo da programação dos eventos existentes no
objeto:
1. Se dentro de um evento da web panel ter o comando For each line, todas as variáveis que estão dentro do
grid passam a ser de entrada. É possível indicar neste caso quais são as variáveis que não podem ser
modificadas através da propriedade ReadOnly.
2. Se dentro da fila tem algum controle com um evento click, dblClick, etc.. associado (ou evento de usuário
especificado na propriedade OnClickEvent), acontecerá o mesmo.
14. 343
Continuamos ampliando nosso exemplo; agora queremos que o usuário possa selecionar uma linha do grid
(um cliente) e pressionando botão ‘Select customer’ para chamar a web panel que havíamos implementado
anteriormente.
Neste exemplo vemos duas funcionalidades:
• A necessidade de colocar uma coluna no grid oculta (não visível).
• Permitir que o usuário selecione uma linha do grid para fazer algo com ela.
Por que colocar a coluna correspondente a CustomerId e ocultá-la, ao invés de não agregar o atributo? Faça a
seguinte reflexão: o atributo CustomerId enviado por parâmetro ao executar o evento ‘Select customer’, de
onde é extraído? Da base de dados? Não, é o que está carregado no grid. Mais especificamente, para cada
grid existirá um arquivo temporário que contem a quantidade de colunas que o grid possuir, visíveis e ocultas.
Quando o usuário seleciona no grid a segunda linha, e pressiona o botão ‘Select customer’, está posicionado
nesse arquivo temporário, correspondente a essa linha (e nunca na base de dados!). É por esta razão que se
não colocarmos nenhuma coluna correspondente a CustomerId no grid, não estaríamos passando valor algum
a CustomerView.
Para que o usuário possa selecionar uma linha do grid, é suficiente ‘prender’ a propriedade ‘AllowSelection’ do
grid.
15. 344
Como GeneXus determina uma tabela base para percorrer automaticamente para carregar o grid da web
panel?
Se existir algum atributo em pelo menos um dos 3 lugares mencionados, GeneXus poderá encontrar a tabela
base. Para determinar a tabela base, ele extrai os atributos encontrados ali (parte fixa do Form, no Grid, tanto
nas colunas como nas propriedades Order, Conditions ou using Data Selector, e nos eventos programa
programados no selector de Eventos, somente os atributos que estejam ‘soltos’ dentro do evento, isto é, fora
de um comando for each de acesso a base de dados), e determina a mínima tabela estendida que os
contenha. A tabela base dessa estendida, será a percorrida automaticamente e carregada com o Load.
Observe que somente programamos o evento Load para tomar a decisão para cada línea que vai ser
carregada no grid, que habilitará ou não para a mesma variável &select que permitirá ao usuário marcar o
check box.
Importante: A forma de determinação da tabela base de um grid dependerá se existir outro grid na web panel
ou se é o único. O resumo apresentado aqui corresponde a um único grid. Neste caso se diz que a própria
Web panel tem tabela base. É a do grid. Quando existir mais de um grid na web panel, isto não vai ter
sentido, e cada grid passará a ter cada grid passará a ter ou não tabela base. Veremos a forma de
determinação das tabelas bases nesse caso, quando tratemos o caso de múltiplos grids em uma web panel.
16. 345
Estamos apresentando aqui outro exemplo, para que possamos observar um caso que surge a necessidade
natural de implementar um grid sem tabela base.
O caso de implementação natural de um grid com tabela base, é quando deseja que seja carregado para cada
registro de uma tabela, uma linha do grid (1 registro – 1 linha). No caso que se quer carregar uma linha do grid
como produto a ser lido de vários registros da base de dados (N registros – 1 linha), como produtos de
cálculos, etc., é mais natural implementar o grid sem tabela base.
O caso do exemplo: não queremos carregar para cada fatura uma linha, mas sim queremos agrupar as faturas
por data, e para cada grupo, carregar uma linha que some seus valores. Estamos falando de um controle de
corte. Se tivéssemos que implementar uma listagem PDF ao invés de uma web panel, saberíamos como
programar (como o fazemos acima) . Vejamos como implementar com uma web panel...
17. 346
O objetivo do comando LOAD é agregar um linha num grid. É necessário quando o grid não tem tabela base,
visto que nesse caso não será agregado nenhuma linha de forma automática. O evento Load vai ocorrer uma
vez, e o grid retornará vazio caso não seja programado. Portanto neste caso é imprescindível que seja
programado, de acordo com a lógica correspondente. Uma vez que for atribuído a cada variável seu valor, e se
deseja agredar uma linha ao grid, o comando LOAD deverá ser programado.
O comando LOAD somente pode ser especificado dentro do evento Load do grid de uma web panel.
Observe que neste caso a implementação fica por conta do analista. Frente ao caso do grid com tabela base,
neste GeneXus realiza menos inferências.
18. 347
No caso de um grid sem tabela base, os filtros dos dados são programados dentro do código implementado
para carga (o do Load). Aqui não tem o refresh automático. Isto é, quando o usuário modifica os valores das
variáveis que intervém nos filtros, GeneXus não sabe que tem que voltar a carregar o grid.
Para isso deverá, por exemplo, agregar um botão associado ao evento Enter, ou a um evento de usuário, sem
código, devido ao fato que somente precisamos dele para que um Refresh seja realizado, ou seja, para que o
servidor volte a carregar a web panel.
Sobre os eventos disponíveis e a ordem em que são disparados, estudaremos em seguida.
19. 348
Em toda Web panel existem eventos do sistema que podem ser programados. Alguns ocorrem sempre, em
cada execução da web panel (como o Start, Refresh, Load), outros se forem declarados e o usuários
realiza as ações necessárias para provocá-los (Enter, definidos pelo usuário, TrackContext).
Assim mesmo, quase todos os controles que aparecem no form brindam a possibilidade de disparar um evento
quanto o usuário faz clic com o mouse (os hiper-links aparecem em execução); de duas maneiras
diferentes:
1. Editando as propriedades do controle (F4), e definindo um evento de usuário na propriedade
OnClickEvent, ou associando o evento Enter ou o Refresh.
2. Dando um nome ao controle e na seção de Eventos programando:
Event nomeControl.click
…
Endevent
Com esta última alternativa não teremos que definir um evento de usuário, mas sim teremos que
programar o evento click do controle. O mesmo ocorre com os eventos DblClick, RightClick, IsValid...
(quando fizer duplo clique, botão direito, etc.).
Sobre os eventos associados as ações sobre os controles (click, dblclick, drag, drop, etc.) não veremos no
curso presente. Em nosso wiki tem informação detalhada, assim como no Help de GeneXus.
Sobre o evento TrackContext somente mencionaremos que é possível detectar mudanças no valor de um dado
controle (grid, variável, etc.) e nesse caso disparar este evento baseado ao valor modificado, tomar uma
ação.
20.
21. 350
Quando a web panel é com tabela base, ao produzir-se o evento Refresh se acessa a base de dados, a essa
tabela base (associada a web panel), e se percorre carregando os registros que cumpram as condições
(conditions do grid e gerais). Vai ocorrer nesse processo um evento Load para cada registro em que estiver
posicionado, imediatamente antes de carregá-lo. Isto nos permite realizar alguma operação que requeira
desse registro ( e de sua estendida), antes de efetivamente carregá-lo no grid. Imediatamente depois de
executado o código associado ao evento Load, será carregado a linha do grid e o ponteiro é passado ao
seguinte registro da tabela base, para realizar o mesmo (evento Load, carga da linha). Este processo se
repetirá até carregar todas as linhas do grid.
Se uma web panel é sem tabela base, GeneXus não pode determinar automaticamente uma tabela da base de
dados a percorrer para mostrar a informação que se apresenta no form. Neste caso no form somente
aparecem variáveis (e não atributos) e também vão ocorrer os eventos Refresh e Load, somente que o evento
Load é executado uma única vez, visto que não estará posicionado em nenhum registro de nenhuma tabela.
Dentro desse evento a carga terá que ser codificada, que pode ser que precise acessar a base de dados (ex:
comando for each) o não (vamos supor que seq queira carregar o grid com informação obtida ao percorrer um
SDT collection, efetuar alguma transformação sobre seus itens ... ou carregar linhas no grid produto de
cálculos). O controle da carga do grid, neste caso fica nas mãos do analista, utilizando o comando Load. Este
comando somente é válido dentro do evento com o mesmo nome. Note como no caso do grid com tabela base,
este comando não é necessário.
22. 351
A propriedade Automatic Refresh que se encontra a nível da Web Panel pode tomar os seguintes valores:
• When variáveis in conditions change (valor por default): automaticamente provocam o refresh, se dispara
o evento Load carregando-se o grid segundo os novos valores das variáveis.
• No: para que o conteúdo do grid se renove depois de alterar os filtros, o usuário deve realizar uma ação:
Se o grid é com tabela base:
• As alterações nas variáveis dos filtros se detectam automaticamente.
• Ao pressionar a tecla Enter, se dispara o Refresh da página (não o código do evento Enter, ainda
que esteja programado).
• Ao fazer click num botão ou numa imagem associados a um evento de usuário, imediatamente
depois de alterar o valor de uma variável das conditions do grid, se executa este evento e atualiza
imediatamente depois a página. Se o evento for o Enter, este evento NÃO se executa.
Se o grid é sem tabela base:
• As alterações nas variáveis dos filtros NÃO se detectam automaticamente
• O usuário deve fazer click no botão ou na imagem associados a um evento Refresh ou a um
evento de usuário que chame um Refresh.
23. 352
Os eventos disparados e sua ordem depende se a web panel está sendo aberta (Get) ou se já estava aberta e
está efetuando uma ação posterior a um botão (Post).
Acima mostramos com exemplos o caso geral.
1a. vez: Start + Refresh + Load
N-ésima vez: Start + Leitura de variáveis da tela + Evento que produziu o Post + Refresh + Load.
Este é o caso geral... existe uma exceção...
24. 353
Internamente GeneXus determina as entradas e saídas de cada evento. Se em suas entradas, se requerem
que ações sejam executadas no Server, então o evento é executado no Server. Por exemplo, se entre as
entradas de um evento de usuário X, se encontra alguma das saídas do evento Start (do server), então o
evento de usuário é executado no Server.
Se o código do evento não requer que seja executado no servidor, então por performance, será executado no
cliente, como código javascript.
De todas as maneiras o analista GeneXus não deve se preocupar com estes assuntos, visto que em todo caso
será o GeneXus que terá a inteligência de resolver onde vai executar o evento.
25. 354
Aqui apresentaremos um exemplo que reúne os dois casos que viemos estudando: a web panel mostrada em
execução tem dois grids paralelos: um que mostra informação dos clientes do sistema, e outro que mostra
faturas, totalizadas por dia.
No nosso caso, queremos além disso relacionar os dados, de tal maneira que quando o usuário seleciona um
cliente, sejam mostradas somente as faturas desse cliente. Incluso ao estabelecer filtros de datas, também
queremos que vá para o cliente selecionado (e não para todos os clientes).
Quando uma web panel contem mais de um grid em seu form, GeneXus não determina uma única tabela
base associada para web panel, mas sim uma tabela base associada a cada grid.
Atributos que participam na determinação da tabela base de cada grid:
• Os incluídos no grid (são levados em consideração os atributos visíveis como os não visíveis,
ocultos/hidden)
• Os referenciados na Order e Conditions locais do grid
A diferença do que acontecia para uma web panel com somente um grid, no caso de múltiplos grids os
atributos da parte fixa da web panel não participam na determinação da tabela base de nenhum deles, mas
deverão pertencer a tabela estendida de algum (para que seja possível inferir seus valores).Caso isso não seja
respeitado, ao especificar a web panel, se mostra na listagem de navegação resultante, um warning advertindo
desta situação.
Os atributos utilizados nos eventos da web panel tampouco participam na determinação da tabela base de
nenhum dos grids. Os atributos que se inclui nos eventos fora de comandos for each, deverão pertencer a
tabela estendida de algum dos grids (da mesma forma como da parte fixa).
26. 355
Esta web panel poderia ter sido implementada de diferentes formas e obtendo o mesmo resultado na
execução.
Acima podemos ver a implementação mais natural: o primeiro grid tem tabela base e o segundo não tem. Mas
poderia ter sido implementada de forma contrária, com variáveis no primeiro grid e tendo que realizar a carga
dos clientes a mão no Load, e atributos no segundo grid, e algumas coisas a mais para obter o controle de
corte, sendo um grid com tabela base. Ou qualquer combinação (ambos grids com tabela base, ou nenhum
com tabela base).
O importante é, uma vez escolhida a implementação mais natural ao caso, realizá-la corretamente.
Em qualquer dos casos, ainda que a informação a ser carregada em mais de um grid se encontre relacionada
na base de dados, GeneXus não assume nenhuma relação entre os dados na hora de carregar um grid e o
outro. É análogo o caso de um par de for eachs paralelos no Source de um procedimento.
Acima podemos ver a web panel que temos o grid com os grids, agregamos a parte de visualização de faturas
por data que implementamos na web panel. Mas não basta simplesmente unir as duas web panels... para
poder relacionar as cargas dos grids, a lógica deve ser agregada. Em nosso caso desejamos que uma vez que
selecionarmos um cliente do primeiro grid, certa lógica precisa ser agregada. Em nosso caso desejamos que
uma vez um cliente for selecionado no primeiro grid, as faturas carregadas no segundo grid não sejam de
todos os clientes, mas somente do selecionado.
Para isso devemos ter duas coisas: agregar uma variável &CustomerId para armazenar o id do cliente
selecionado ao pressionar ‘Select customer’, e depois agregar um filtro pelo valor dessa variável quando se
carrega o grid de Invoices. Assim mesmo precisa obrigatoriamente colocar essa variável no form para que tudo
funcione corretamente ... como esperamos... e na análise abaixo encontraremos a razão.
27. 356
Vamos analisar o que acontece quando a web panel é executada pela primeira vez.
Primeiro o evento Start é executado, em nosso caso a variável &CustomerId é ocultada.
Podemos ver na imagem, que um evento Refresh genérico é produzido, depois serão produzidos as cargas de
todos e cada um dos grids encontrados na web panel, da esquerda para a direita de cima para baixo.
Um evento Refresh próprio ocorre e o evento Load (se possuir tabela base são N vezes e se não tiver tabela
base somente 1 vez).
Observe que nosso caso, o grid de cliente tem condições para serem carregadas, pelas variáveis de filtro
&customerName e &countryName, não são aplicadas se estiverem vazias (visto que ambas cláusulas
condicionais tem when not &var.IsEmpty())
O segundo grid é sem tabela base, mas como já vimos, o evento Load era executado um for each com
cláusulas where, serão carregadas somente aquelas linhas que as condições são cumpridas. São três:
where InvoiceDate >= &startDate when not &startDate.IsEmpty()
where InvoiceDate <= &endDate when not &endDate.IsEmpty()
where CustomerId = &customerId when not &customerId.IsEmpty()
Observe que nesta primeira execução &customerId está vazio, o filtro não é aplicado e todas as faturas do dia
é carregada, de todos os clientes.
28. 357
O usuário seleciona o cliente do grid o cliente correspondente da linha e pressiona o botão ‘Select customer’.
Uma ação é detectada e ocorre um post ao servidor, quem executa o Start (ocultando a variável), depois as
variáveis da tela são lidas (&customerId no momento está vazia, são consideradas não somente as variáveis
da tela, as que são definidas, mas também a informação completa da linha selecionada pelo usuário com o
mouse, entre ela, o valor de CustomerId, coluna do grid), depois o código do evento que produziu o post é
executado, no nosso caso, ‘Select customer’. Aqui a variável &customerId toma o valor do CustomerId da linha
escolhida. Depois ocorre o evento Refresh geral que dispara o Refresh e Load de cada grid.
Portanto, cada grid é executado executando as conditions. O primeiro se carregado como antes, porque
nenhuma de suas conditions variou. O segundo, agora se tiver um valor para &customerId, somente será
mostrado as faturas do cliente.
Você poderia se perguntar porque precise colocar a variável oculta no form. Simplesmente porque não se pode
usar como variável dentro do programa, se não estiver no form e torná-la invisível. Todavia com esta segunda
execução não podemos responder a pergunta. De fato, se analisarmos, pode ser visto facilmente que teríamos
o mesmo comportamento se somente fosse atribuído valor a variável no ‘Select Customer’ sem colocá-la no
form.
Vamos ver o motivo com a execução seguinte....
29. 358
Agora o usuário já selecionou o segundo cliente, e o que deseja fazer é filtrar suas faturas por data (não quer
visualizar todas).
Para isso especifica os filtros de data, e pressiona o botão ‘Search’, que produzirá um post no servidor.
Então o código do Start é executado, depois são lidas as variáveis da tela: aqui está o motivo de ter colocado
&customerId no form. O valor de &customerId é lido, permanecendo até que o usuário não selecione outro
cliente do grid e pressionar o botão ‘Select customer’... esta variável presente no form, é a forma de manter a
memória em execuções.
Lembre que cada vez que se faz um post ao servidor, é uma nova execução da web panel, já que as variáveis
começam novamente vazias. Por isso que o segundo passo: “Leitura de variáveis da tela” é fundamental.
Agora sim, seguindo o exemplo, as variáveis da tela são lidas &customerId invisível (visible=0), junto com as
variáveis &startDate e &endDate.
E depois, como sempre, a carga é executada (Refresh genérico + Refresh e Load de cada grid).
Alterando as condições do for each que carrega o segundo grid, agora aparece somente as faturas do segundo
cliente, entre as datas estipuladas pelo usuário.
Se agora o usuário quiser alterar o cliente, para ver suas faturas, será feito a seleção no grid de clientes e ao
pressionar ‘Select Customer’, o processo começa novamente como vimos na 2da. execução.
E como fazemos para voltar a trabalhar com as faturas de todos os clientes e não de um?
O que acontece se o usuário não selecionar nenhum cliente do grid com o mouse e pressionar ‘Select
Customer’. O valor da variável &CustomerId fica vazio, pois CustomerId não vai ter valor.
Por este motivo, o botão ‘Select Customer’ poderíamos chamar ‘Select/Unselect’.
30. 359
Os botões inseridos dependem da quantidade de registros e da quantidade de linhas do grid.
32. 361
Dois tipos de grid:
• Grid padrão: que vimos até agora, em Transações e Web Panels
• Grid Free Style
Estes grids, agregam potência ao desenho de aplicações web, permitindo ao desenvolvedor maior liberdade na
hora do desenho.
O grid Free Style permite ao usuário definir o formato dos dados a serem mostrados de uma forma menos
estruturada que o grid padrão.
O grid Freestyle é basicamente uma tabela que podem inserir os atributos/variáveis, text blocks, imagens,
botões, web components, embedded pages, grids freestyle e/ou grids que serão mostrados posteriormente na
tela. Neste caso para poder visualizar as propriedades tem que selecionar a tabela onde se encontram os
atributos/variáveis.
No exemplo apresentado acima queremos mostrar alguma informação dos países. O atributo CountryFlag foi
incluído na transação “Country” para armazenar a foto da bandeira de cada país (é um atributo de tipo Blob).
Mas não queremos mostrar a informação como o faríamos em um grid padrão, cada elemento de informação
em uma coluna diferente do grid. Aqui queremos mostrar a foto e abaixo o identificador e nome do país.
O comportamento das variáveis dentro de um grid Free Style é análogo ao apresentado dentro de um grid
padrão, portanto também são de ingresso se existe um For each line ou For each line in <grid> dentro de
algum evento, ou se associa um evento a qualquer controle da fila. Novamente este comportamento pode ser
modificado, agregando a regra noaccept ou alterando a propriedade Read Only.
33. 362
Este caso de grids aninhados é igual o de for each aninhados em um procedimento: ou seja, aqui as cargas
estão relacionadas, e no Grid2 é carregado todos os clientes pertencentes ao país carregado no Grid1.
A ordem de execução dos eventos estará aninhada:
Refresh (genérico)
Grid1.Refresh
Grid1.Load carga de um país
Grid2.Refresh
Grid2.Load carga de cliente do país
Grid2.Load carga de cliente do país
Grid2.Load carga de cliente do país
Grid1.Load carga do país seguinte
Grid2.Refresh
Grid2.Load carga de cliente do país
Grid2.Load carga de cliente do país
Grid2.Load carga de cliente do país
.....
35. 364
Os objetos web podem ser definidos com três tipos diferentes, configurável na propriedade Type do objeto.
Para uma web panel poderá ter um dos valores:
• Component: (transação ou web panel, que a partir daqui poderá ser incluído em outro web object)
• Web Page (isto é, o objeto será uma transação ou web panel tal como temos trabalhado até o momento)
• Master Page
Em seguida introduziremos a Web Panel tipo: Component”, “Master Page” e sua utilização.
40. 369
Ter um look&feel consistente é hoje em dia um dever de toda aplicação Web.
Criar e manter cada página de uma aplicação Web assegurando a consistência com o resto do site leva grande tempo
de programação.
Ao criar uma base de conhecimento GeneXus X criará também dois objetos de tipo Mastet Page:
• ApplMasterPage: Para a aplicação
• PromptMasterPage: Para os prompts
Uma web panel, AppMasterPager categorizado como “Master Page” será criada com tudo, ou seja, o Layout e
comportamento comum a todas as páginas do site, e no mesmo se deixa um espaço para carregar a página
correspondente (o conteúdo variável do site). Corresponde ao controle especial ContentPlaceholder. As páginas web
que implementam o conteúdo variável, se implementam como Web Panels ou Web Transactions comuns e correntes
(é do tipo “Web Page”, ver página anterior), e se associam a Master Page, de maneira que cada vez que se executem,
são carregadas com esse “contexto”. Agora faça o seguinte, abra qualquer objeto GeneXus com form (transação ou
web panel) criada na KB, e veja o valor da propriedade Master Page.
As Master Pages fornecem uma forma de centralizar o layout e o comportamento comum em somente um objeto e
reutilizá-lo em todo outro objeto sem ter que programar. Isto significa que a modificação de alguma parte do layout ou
do comportamento comum é tão fácil como modificá-la num único objeto e pronto!.
Numa mesma base de conhecimento podem ser definidas tantas Master Pages quanto desejar.