Relatórios no Maker – 2


Neste post darei continuidade ao post anterior sobre criação de relatórios no Maker. Abordarei aqui a criação de filtros e o uso de sub-relatórios. No RB10 o mecanismo de filtros é um pouco diferente do mecanismo de filtro do RB7, agora é possível criar filtros com mais liberdade, apesar de, às vezes, isso requerer mais trabalho por parte do desenvolvedor. Já a funcionalidade de sub-relatórios não mudou muito, de qualquer forma, irei mostrar como utilizá-la no RB10.

Criando Filtros no RB10

Criar um filtro para um relatório no Maker não é nada mais do que definir uma consulta SQL, se você possui uma query que roda corretamente no SGBD ou no Executor de Scripts do Maker, essa mesma query poderá ser criada no construtor de consultas. Cada campo no seu where que terá que ser informado pelo usuário deverá ser convertido em um parâmetro no construtor de consultas SQL do RB10.

Para definir um parâmetro na consulta SQL dentro do RB10 é utilizada a seguinte convenção: dois pontos + nome do parâmetro. Ex: ‘:codigoDoPedido’.  Um parâmetro pode ser de três tipos: Caixa de Texto, Data e Lista Dinâmica. O Tipo de Caixa de Texto é utilizado quando o usuário irá digitar qualquer valor para realizar o filtro, letras ou número, o tipo Data exibe uma caixa de texto e um ícone para seleção visual da data em um calendário, e o tipo Lista Dinâmica define uma lista na qual o usuário irá buscar o registro que servirá de filtro para a geração do relatório. O parâmetro possui um Título, que será exibido para o usuário e um Valor Padrão. Além disso, cada parâmetro pode ser marcado como: 1) Requerido, o parâmetro não pode ser passado em branco; 2) Somente Leitura, o parâmetro não é modificado pelo usuário; 3) Oculto, o parâmetro não é exibido para o usuário. Se o parâmetro for Somente Leitura ou Oculto, ele deverá possuir valor padrão ou receber seu valor da tela ou do fluxo chamador, caso contrário permanecerá nulo. Nesta parte do post vou falar sobre os tipos de filtros mais comuns e como fazê-los utilizando os parâmetros citados.

Filtro Simples com um Campo

Este é o tipo de filtro mais comum, no exemplo da Figura 1, temos um cadastro de Pedido de Venda e queremos invocar o relatório em questão a partir do formulário do pedido, portanto precisamos filtrar o relatório pelo código do pedido.

Figura 1 – Tela de Pedido de Venda e Impressão do Pedido

Para isto definimos o parâmetro ‘:codigoDoPedido’ na coluna ‘Critério’ da consulta SQL. Feito isto, é possível definir como este parâmetro será apresentado ao usuário, clicando no botão Parâmetros, indicado na Figura 2-a. No caso do nosso exemplo, vamos definir um parâmetro do Tipo Lista dinâmica e preencher o título com: ‘Selecione o Pedido’, a consulta que irá popular esta lista dinâmica é apenas uma seleção da coluna código da tabela de pedidos, como mostra a Figura 2-b. Na figura 2-c, é possível visualizar a chamada ao relatório no menu do webrun e o resultado de sua visualização com o filtro efetuado.

Figura 2 – Relatório Pedido de Venda. a) Definição do parâmetro; b) Configuração do parâmetro; c) Resultado da geração do relatório.

Filtro do Formulário para o Relatório

Este filtro é útil quando se deseja que o usuário possa emitir um relatório ao navegar entre os registros de uma tela e que este relatório saia filtrado com o registro no qual a tela está posicionada. Esta é uma funcionalidade nativa do webrun, sempre um relatório é invocado a partir de um formulário e, este relatório possui parâmetros com os mesmos nomes de campos da consulta do formulário, a passagem de parâmetro automática é realizada, e quando a tela de pré-visualização do relatório é exibida, os parâmetros em questão nem são mais exibidos para o usuário. Na figura 3-a, o relatório do item anterior foi chamado a partir da tela correspondente, como era de se esperar, o filtro não foi preenchido automaticamente, pois o nome do parâmetro definido foi ‘:codigoDoPedido’, se mudarmos o nome deste parâmetro para ‘:COD_PEDIDO’, mesmo nome do campo na tela, podemos conferir que o parâmetro foi passado automaticamente, como mostra a Figura 3-b.

Figura 3. Exemplo de passagem de parâmetro do formulário para o relatório.

Filtro com Datas

Este é um tipo de filtro bastante comum, é utilizado quando se deseja que o usuário filtre os dados por um período de datas, a princípio este parece ser um filtro como o que foi explicado no item “Filtro Simples com um Campo” deste post, mas, vamos ver que temos que ter algumas preocupações na criação desse tipo de filtro. Vamos tomar como exemplo aqui um relatório de Resumo dos Pedidos, este relatório irá exibir os Pedidos de Venda sem os itens, listando apenas a data de emissão, total e quantidade de itens. Vamos supor que para este relatório foi pedido um filtro pela data de emissão. Este filtro ficaria como mostra a figura 4-a. Olhando o código SQL desta consulta pode-se ver que o que se deseja fazer aqui não é nada além de uma simples consulta SQL com where: select cod_pedido, {…} from exe_pedido_venda where ped_data_emissao >=:inicio and <=:fim. Este filtro funciona, porém, se o campo ‘ped_data_emissao’ for armazenado com data e hora alguns registros podem ficar de fora, por exemplo. Supondo que um registro tenha data de cadastro igual a 26/08/2011 15:54, e eu tenha emitido o relatório passando como filtro: Início=25/08/2011; Fim=26/08/2011, este registro não será listado, pois quando eu não preencho a hora no relatório, o componente data entende que o horário é 00:00:00, e como 26/08/2011 00:00:00 é anterior a 26/08/2011 15:54, este registro estaria fora do período definido pelo usuário e isto pode ser indesejável caso a hora da venda não seja relevante. Para resolver essa questão basta converter o campo data que será comparado para um formato sem hora, como mostra a figura 4-b, para o banco de dados SQL Server 2005.

Figura 4 – Exemplo de Filtro com Datas

O filtro com datas pode ainda ter outras características, por exemplo, pode ser desejável que, se o parâmetro fim for deixado em branco o relatório deve exibir todos os registros a partir do campo início. Neste cenário, o campo início deverá ser marcado como obrigatório e o campo fim como opcional. Além disso, na própria consulta deverá ser criado um mecanismo para atender esse requisito, neste caso o seguinte comando na coluna critério resolve o problema: >=:inicio and (<=:fim or :fim is null). Este comando realiza o filtro do parâmetro início obrigatoriamente, mas, o parâmetro fim só é checado se ele possuir valor, caso não possua, seu valor é ignorado, vide Figura 4-c. Esta forma de criar o filtro é útil para qualquer parâmetro que seja opcional, não só para datas. Utilizando esse mecanismo é possível criar um filtro entre datas ainda mais versátil, um filtro onde, se o início for preenchido e o fim estiver nulo, o filtro é efetuado a partir do início, se o fim estiver preenchido e o início estiver nulo, os registros são filtrados até o fim, e, se ambos estiverem nulos, todos os registros são exibidos. O seguinte trecho de código realiza este filtro: (>=:inicio or :inicio is null)  and (<=:fim or :fim is null), como mostra a Figura 4-d.

 

Utilizando a funcionalidade Sub-Relatório

O uso de sub-relatórios é necessário quando um relatório precisa exibir um conjunto de registros dentro de uma única faixa do relatório principal. É possível criar sub-relatórios de forma aninhada, e utilizar tantos quantos forem necessários para chegar ao resultado desejado em tela. O que precisa ser observado quanto ao uso de sub-relatórios é a definição da consulta, cada sub-relatório deve ter uma fonte de dados associada, que por sua vez pode ter ligação com a fonte de dados principal. Para exemplificar o que foi dito vamos tomar como base o relatório Pedido de Venda citado anteriormente, vamos supor que para cada produto listado neste relatório seja necessário listar as informações nutricionais do mesmo. Para isto, vamos utilizar um sub-relatório. O primeiro passo é definir outra consulta que irá retornar os registros das informações nutricionais por produto, esta consulta deverá ter o código do produto para que a associação com o produto da consulta principal seja feita, como mostra a figura 5-a. Após definir a consulta, basta adicionar um componente sub-relatório, que uma nova guia irá aparecer no rodapé da página, como está indicado na figura 5-b. Ao clicar nessa guia, é possível definir o conteúdo do sub-relatório, a primeira ação a ser feita é definir a fonte de dados da consulta clicando em Relatório->Dados e escolher o condutor de dados. Caso não haja mudança no nome da consulta, o RB10 irá criar os nomes de forma seqüencial: consulta, consulta1, consulta2, etc. É possível alterar esse nome na aba consulta da tela da consulta SQL. Feito isto, é possível definir o conteúdo do sub-relatório, que é um relatório completamente novo, podendo conter grupos e outras sub-consultas. Na figura 5-c é possível visualizar o resultado do relatório com sub-relatório.

Figura 5 – Relatório com sub-relatório

Perceba que na situação do relatório explicada acima é possível resolver o problema utilizando uma única consulta e a funcionalidade de Grupos (veja este post), pois, agrupando os dados por produto, é possível colocar na faixa detalhes os registros dos valores nutricionais. Porém, existem situações onde a utilização de sub-relatórios é a única solução, vamos supor que seja necessário adicionar ao sumário do relatório anterior as faturas geradas pelo pedido. Neste caso, somente um sub-relatório atende a este requisito, pois, se tentássemos utilizar grupos a consulta iria retornar dados incorretos, pois para cada fatura existente os itens seriam replicados. Portanto, para resolver este problema bastaria criar uma nova consulta e criar um sub-relatório na faixa sumário. Salvo os casos onde o uso de sub-relatório é obrigatório, cabe ao desenvolvedor avaliar quando utilizar grupos ou sub-relatórios, em consultas complexas, que necessite de 5 ou mais grupos, talvez seja interessante fragmentar a consulta utilizando um sub-relatório para facilitar a visualização e manutenção.

Conclusão

O uso de filtros e sub-relatórios, brevemente exemplificados neste post, juntamente com as funcionalidades de agrupamento citadas no post anterior consistem nas principais funcionalidades para a criação de relatórios no Maker utilizando o RB10. De posse destes conhecimentos e com um pouco de mão na massa, é possível criar relatórios com uma maior complexidade e, conseqüentemente, mais úteis.

Relatórios no Maker – 1


Olá, dando continuidade aos posts sobre as funcionalidades do Maker, vou falar um pouco sobre a criação de relatórios. O Maker utiliza o gerador de relatórios RB (Report Builder) para prover tal funcionalidade na criação dos sistemas. Nas versões 2.4.x do Maker era possível criar apenas relatórios utilizando o RB7, que, apesar de ser completamente funcional, apresentava diversos problemas relacionados a bug’s sem motivo aparente, e dificuldades operacionais básicas (como a ausência de Ctrl+Z). Com a disponibilização do RB10 muito se melhorou no aspecto de desenvolvimento de relatórios com o Maker, o gerador se tornou mais estável, principalmente no que diz respeito à criação da consulta, porém, quem ainda possui relatórios legados, precisa lidar com o RB7 ou migrar gradativamente seus relatórios para o RB10 (foi o que fiz). Neste post darei dicas de como migrar seu relatório do RB7 para o RB10 e como utilizar a funcionalidade de agrupamento.

 Migrando relatórios do RB7 para RB10

O primeiro passo é recriar suas consultas no novo relatório. O ideal aqui, para acelerar a migração é recriar a consulta utilizando os mesmos aliases para os campos, de forma que, quando os componentes visuais do relatório forem copiados, as referências sejam mantidas. No caso de consultas complexas ou caso estejam sendo utilizados muitos aliases para os campos, recomendo criar uma view com exatamente a consulta que está definida no RB7, copie o SQL para um editor e cria sua view, no RB10, basta criar a consulta e selecionar todos os campos desta view, e, claro, refazer seus filtros e a ordenação, uma vez que views não podem ter order by.

Uma vez definidas as consultas, vem o passo mais importante deste processo: para que não seja necessário recriar o relatório do zero, é possível copiar os componentes do relatório antigo para o relatório novo. Porém, antes de fazer isto, é preciso garantir que as faixas do relatório estejam configuradas exatamente da mesma forma que estão no relatório original, caso contrário o posicionamento será desperdiçado, pois os objetos ficarão sobrepostos, veja a Figura  1.

Figura 1. Exemplo de Relatório no RB10 com componentes sobrepostos.

Para começar, recrie os grupos do relatório, se estes existirem, para que o novo relatório possua exatamente as mesmas faixas que o relatório antigo. Não se esqueça também de deixar a orientação correta: retrato ou paisagem. Depois de recriar as faixas, certifique-se para que cada uma delas possua o mesmo tamanho que a faixa equivalente no outro relatório, vide figura 2. Feito isto, vá ao relatório no RB7, aperta as teclas Ctrl+A para selecionar todos os componentes, depois aperte Ctrl+C, em seguida vá ao relatório no RB10 e aperte Ctrl+V, e verifique novamente o tamanho das faixas para manter a aparência do relatório.  (vide figura 3a)

Figura 2. Comparação entre tamanho das faixas de relatórios no RB10 e RB7.

Neste ponto, os componentes visuais foram todos copiados e todo o trabalho de posicionamento foi reaproveitado. Entretanto, as referências à fonte de dados estão vazias, vide figura 3b. Neste passo, é necessário clicar em cada componente que tem ligação com o banco e selecionar a consulta. Repare na figura 3c, que, ao selecionar a consulta, o campo foi automaticamente preenchido, devido ao fato de que os aliases utilizados permaneceram os mesmos. Após esta etapa, o relatório estará quase pronto, se o seu relatório no RB7 possuir alguma operação feita em Object Pascal da aba ‘Cálculo’ do gerador, estas podem ser copiadas diretamente para a faixa correspondente. Feito isto, salve seu relatório e está pronta a migração!

Figura 3. Relatório no RB10 com componentes copiados do RB7.

Como Utilizar a funcionalidade ‘Grupos’

Como o nome já sugere, a funcionalidade Grupos permite um agrupamento de registros no ambiente do relatório, esta funcionalidade baseia-se em adicionar duas faixas novas ao corpo do relatório, uma antes (cabeçalho) e outra depois (rodapé) da faixa Detalhes – que é a faixa que exibe os dados de cada registro da consulta. Diferentemente do group by do SQL, o agrupamento no relatório não tem papel de agregação, ele não totaliza registros, apenas organiza a exibição dos dados. A adição de grupo é feita no menu Relatório->Grupos, presente na aba Desenho. Cada grupo é definido por um campo da consulta, e a sua exibição é feita pelo RB10 da seguinte forma:  para cada registro, o gerador de relatório verifica se houve uma mudança do valor do campo definido como grupo, se sim, as faixas cabeçalho e rodapé do grupo são inseridas, senão, a faixa detalhe é exibida normalmente. Por este motivo é indispensável que a ordenação da consulta obedeça à mesma ordem definida nos grupos, caso contrário, o agrupamento dos registros no relatório poderá ficar incorreto. A utilização de grupos é útil em qualquer situação onde haja relação hierárquica entre campos de um consulta, como por exemplo: funcionários por setor, alunos por turma, usuários por sistema, etc.

Tome como exemplo um relatório de funcionários por setor, onde exista mais de um funcionário em cada setor, e seja exibido: nome do setor, nome do funcionário, salário do funcionário. Além disso, é desejável que para cada setor seja informado: quantidade de funcionários, valor total de salários pagos. Para este exemplo, bastaria criar um grupo com o campo descrição ou código do setor (não esqueça de ordenar a consulta pelo mesmo campo informado no grupo). No cabeçalho do grupo, adicionaríamos o nome do setor, e no rodapé, utilizando o componente campo calculado, totalizaríamos a quantidade de registros e o somatório dos salários. Feito desta forma, a consulta pode ter N setores, que, para cada um, as informações citadas serão exibidas corretamente. Veja o relatório citado na figura 3a e o resultado na figura 4.

Figura 4. Resultado da geração do Relatório Funcionários por Setor com agrupamento.

O agrupamento também pode ser usado em situações mais complexas, como por exemplo: um relatório que liste os funcionários por setor, setores por departamento, departamentos por unidade, e assim por diante. Para tal tarefa, basta criar os grupos na ordem de agrupamento, da maior granularidade para a menor, o que neste caso seria: unidade, departamento, setor.

 

Este foi o primeiro post sobre relatórios no Maker. Em breve farei outro post sobre este mesmo assunto, mostrando como fazer filtros e a utilização de sub-relatórios.

5 Dicas Rápidas com o Maker


Validação de E-mail

Para validar email no Maker, crie um fluxo que recebe por parâmetro o email que se deseja validar, e utilizando a função ‘Validar Texto Utilizando Expressão Regular’, submeta o email passado por parâmetro para a seguinte expressão regular: [a-zA-Z[-_.]]+@[a-zA-Z[-_.]]*[a-zA-Z[-_]] ou outra de sua preferência.

Figura 1 – Fluxo para validar e-mail

Validação de componentes de preenchimento obrigatório sem Ligação com o BD

Se você tem em seu sistema alguma tela e precisa validar o preenchimento de campos que não estão ligados ao banco, faça um fluxo genérico, que receba uma lista de componentes separados por vírgula (ou outro caracter de sua preferência), quebre a lista com a função ‘Quebrar Texto’, e itere sobre os elementos da lista com as funções ‘Tamanho da Lista’ e ‘Obter Objeto da Lista’, verificando, para cada item, se o mesmo foi preenchido, com as funções ‘Obter Valor do Componente’ e ‘É Nulo’ e exibindo uma Mensagem de Erro caso o componente em questão esteja em branco. Veja a figura abaixo.

Figura 2 – Fluxo para validação de componentes de preenchimento obrigatório sem ligação com o BD

Função ‘Alerta Aguardando OK’

Recomendo o uso dessa função para debug em fluxos clientes ou servidores. Esta função invoca a função alert() do JavaScript, e, como é uma função nativa no browser ela interrompe de fato a execução do fluxo em questão até que o botão OK seja pressionado. Por isto, em um caso onde você precise verificar os valores em um laço, por exemplo, é mais vantajoso utilizar esta função do que utilizar a Mensagem de Alerta do fluxograma, pois esta não interrompe a execução do fluxo, de forma que as mensagens aparecem sobrepostas na tela, dificultando a depuração. Faça um teste e ateste o que foi dito aqui. J

Lista dinâmica filtrando lista dinâmica em tela

Em boa parte dos sistemas haverá a necessidade em algum ponto de realizar um filtro entre listas dinâmicas, por exemplo: Lista de UF filtrando lista de Municípios, Lista de Representantes filtrando lista de Clientes, lista de disciplinas listando lista de professores, etc. Para tal, basta definir a consulta da lista dinâmica a ser filtrada no Editor de Consultas, utilizando a notação ‘dois-pontos’ + ‘nome do campo’ (:campo) para referenciar um campo qualquer da consulta do formulário no qual a lista se encontra. Veja na figura abaixo, onde é realizado um filtro de municípios por UF utilizando duas listas dinâmicas.

Figura 3 – Filtro entre listas dinâmicas em tela

Lista dinâmica filtrando lista dinâmica em relatório

Da mesma forma como foi descrito no item acima, é comum a necessidade de realizar filtros entre listas dinâmicas nos parâmetros de um relatório. O procedimento é parecido com o que foi citado acima, a diferença aqui é que é utilizada a notação dois-pontos + ‘nome do parâmetro’ (:parâmetro). Veja na figura abaixo, onde é definido um filtro de municípios por UF no gerador de relatório RB10.

Figura 4 – Filtro entre listas dinâmicas em relatório

 

Boas práticas com o Maker 3/3 – Criação de Formulários


Esta é a última parte de uma série de posts abordando o tema Boas Práticas com o Maker. Na primeira parte falei sobre modelagem de bancos de dados, na segunda parte falei sobre programação com fluxos. Neste post falarei sobre criação de formulários, dando algumas dicas de como otimizar o trabalho utilizando os recursos do Maker através de técnicas e uso dos recursos disponíveis.

Quando se está começando a desenvolver um módulo de um sistema ou mesmo um pequeno sistema, é inevitável passar por uma etapa de criação de telas de cadastros simples, geralmente são tipos, status, categorias, etc. Para esta tarefa é interessante utilizar a funcionalidade de criação de Múltiplos Formulários (veja a documentação aqui), já que se trata de telas que não irão sofrer muitas alterações de layout, sendo telas para edição simples de registros. Utilizando este recurso ganha-se muito tempo pelo simples fato de não ser necessário definir cada tela manualmente, criando consultas e posicionando componentes. Para otimizar ainda mais o trabalho, certifique-se de que o Dicionário de Dados (veja documentação aqui) está devidamente preenchido, para que os componentes dos formulários sejam criados com as descrições desejadas.

No post anterior foi abordada a importância da nomenclatura para fluxos, as mesmas regras se aplicam aos formulários, o fato de o Maker permitir a criação de artefatos (formulários, fluxos e relatórios) com descrições alfanuméricas longas requer cuidado, pois formulários com nomes ambíguos podem complicar a vida do desenvolvedor no momento da localização destes artefatos. Por exemplo, em boa parte dos sistemas irá existir um formulário de nome “Itens”. Se no momento em que você necessitar localizar este formulário o Maker lhe exibir três opções com este mesmo nome (sim, o Maker não impede a criação de formulários com mesmo nome!), você vai desejar ter dedicado um pouco mais de atenção a esta questão, pois será necessário abrir cada um para saber qual você está procurando. Por isto, considerando um sistema de automação comercial, caso tenha uma tela para Pedido de Venda e outra para os itens, dê a esta segunda tela um nome completo, de modo a facilitar a sua localização, tal como: ‘Pedido de Venda – Itens’. Se esta tela de itens por sua vez for um sub-formulário que contém uma grade, dê um nome significativo para o formulário que define a grade, como ‘Pedido de Venda – Itens – Grade Parcelas’ por exemplo. Esta prática evitará ambigüidades e facilitará muito a localização dos formulários.

A forma disponibilizada pelo Maker para definição de regras de negócios e ações em um formulário é via fluxo. Por isto, boa parte dos desenvolvedores que migram de outras linguagens para o Maker costuma criar fluxos para todas as operações que eram realizadas com código. Porém, ao mudar para o Maker, é interessante que se estude extensivamente as funcionalidades disponibilizadas pelos componentes que podem ser exploradas sem uso de fluxo, veja algumas funcionalidades úteis por componente abaixo:

  • Botão: possui a propriedade para realizar chamada a um formulário com passagem de parâmetros.
  • Grade: possui a propriedade Grade Mestre, que permite que a efetuação de filtros entre grades em uma mesma tela.
  • Lista dinâmica: possui a propriedade ‘Formulário’, que permite definir um formulário a ser chamado para edição dos registros referentes à consulta da lista.

Para uma lista completa de propriedades dos componentes, consulte a documentação online. Vale aqui dizer ainda sobre os valores padrão nos formulários, é possível defini-los clicando em Definições e em seguida na aba Valores Padrão e Máscaras. Neste momento é exibida uma tela com uma grade que exibe os campos selecionados na consulta do formulário em questão, clicando com o botão direito na coluna ‘Valor Padrão’ é possível associar um valor a um campo. Este valor pode ser o retorno de funções, consulta SQL ou uma constante. Por outro lado, também é possível definir os valores padrão de uma tela criando um fluxo no evento ao navegar, e verificando se o formulário se encontra em modo de inserção.

Neste âmbito, uma boa dica é definir parâmetros para o seu sistema através de uma tabela de parâmetros e obter os valores desejados utilizando a opção Consulta SQL na definição de valores padrão, por exemplo, considere um sistema de vendas, onde por padrão, deve-se dar 5% de desconto em todas as vendas. Se este valor é colocado de forma constante no formulário e um dia o cliente desejar alterá-lo, será necessário acessar o projeto no Maker, alterar o formulário, gerar .war ou exportar .frz, a depender de como publicou o seu sistema (sobre este assunto veja este post) e  por fim, atualizar no cliente. Se, por outro lado, você criou no seu sistema uma tabela para armazenar parâmetros, você poderia alterar este parâmetro em uma simples edição de registro, ganhando tempo e facilitando a manutenção do seu sistema para estes casos.

A criação de formulários no Maker é bastante simples e direta, define-se uma consulta, posiciona-se os componentes na tela, escolhe-se os valores padrão destes componentes, e define-se as regras de negócios, que pode envolver cálculos ou gravação de registros auxiliares no banco de dados. O importante é definir cuidadosamente as regras a serem associadas a um formulário, verificando os eventos disponibilizados pelos componentes e pelo próprio formulário e realizando testes de funcionamento. Questões sobre criação de fluxos e utilização de funções fogem ao escopo desta publicação, mas, é bom ter em mente, que no Maker toda regra é chamada a partir de um evento da tela, para que seu sistema funcione da maneira esperada, conheça todos os eventos que puder para que você tenha condições de projetar a melhor solução para o seu problema.

Um ponto importante ao se tratar de formulários no Maker é a criação de telas de consulta. Nem sempre a aba localizar é suficiente para realizar determinadas consultas, quando se deseja um filtro específico, ou filtragem através de componentes visuais como árvores e grade, ou mesmo por questões de layout. Outras vezes, em tabelas com muitos relacionamentos, a quantidade de campos que se deseja na aba localizar pode tornar a consulta muito pesada, ou simplesmente inviável, por exemplo, considere um sistema de loja, onde se tem um pedido de venda com os seguintes campos: usuário que cadastrou o pedido, vendedor, representante, assistente, tipo de pedido, cliente, endereço de entrega, etc. Agora imagine o que vai acontecer com a consulta da tela se for necessário que todos os campos citados acima apareçam na aba localizar, como são campos que fazem referência a outras tabelas, você irá precisa adicioná-los na consulta, à medida que mais campos forem necessários, mais pesada fica a consulta, o que pode ser notado no tempo de abertura da tela e na navegação entre os registros, além do mais, consultas muito complexas podem provocar outros efeitos indesejados como: replicação ou falta de registros por questões de relacionamento (inner, left, etc). Por estas questões, é interessante pensar em formas bem estruturadas para construir telas de consulta, de modo que a tela na qual se faz a manutenção dos registros fique sempre otimizada.

Quando se está fazendo uma tela de consulta com filtro dinâmico preenchido pelo usuário, quase sempre é necessário utilizar fluxo. Para esta tarefa, as funções: ‘Abrir Consulta’ e ‘Grade – Preencher com Consulta’ podem ser aplicadas. Basta criar um fluxo com estas duas funções, na primeira você faz sua consulta, recebendo os parâmetros da tela, por exemplo, considere um sistema de loja onde você precisa criar uma consulta para listar os pedidos efetuados por vendedor e por período de vencimento. A figura abaixo mostra a tela e o fluxo que realiza a funcionalidade.

Figura 1- Exemplo de Consulta com filtro de data

Cabe ressaltar aqui que, mesmo que a grade da figura acima seja populada pela função ‘Grade – Preencher com Consulta’, este componente ainda precisa de um formulário associado, caso contrário, o componente grade não aparece na tela. A dica aqui é que você crie este formulário com os mesmos campos que sua consulta irá retornar, porém, sem registros, isso pode ser obtido com uma consulta com o limitador de registros ‘TOP 0’. Desta forma, quando o usuário clicar no botão que irá processar a consulta na grade, não haverá uma mudança brusca das colunas que a compõem, tornando a funcionalidade mais natural, visto que, os nomes dos componentes é que irão compor as colunas da grade quando a tela abrir, e, quando a função ‘Grade – Preencher com Consulta’ for chamada, são os aliases dos campos que irão compor as colunas (nesta função também é possível definir manualmente os nomes das colunas, através do seu 4º parâmetro).

Existem casos de consultas onde as propriedades do componente grade são suficientes para efetuar a funcionalidade desejada, como por exemplo, a propriedade ‘Grade Mestre’, ou o uso de parâmetros. Considerando novamente um sistema de loja, onde seja necessária uma consulta a Funcionários por Setor, é possível realizar tal consulta com duas grades, uma com os setores e outra com os funcionários, sendo que, ao clicar em um setor, a grade de funcionários exibe os funcionários daquele setor, como mostra a figura 2-a. Na figura 2-b tem-se uma tela com mesma funcionalidade, mas utilizando um componente do tipo lista dinâmica para filtrar a grade pelo uso de parâmetros.

Figura 2 – a) Exemplo de Consulta utilizando propriedades do componente grade. b) Exemplo de consulta utilizando lista dinâmica e grade.

Se a consulta desejada for o simples retorno de uma view ou consulta SQL, o problema se torna ainda mais fácil de resolver, pois basta criar um formulário sem navegação e sem abas, apenas com um componente grade, e definir a consulta desejada no formulário da grade, que deverá ser editável. A Figura abaixo mostra um exemplo de consulta que exibe todos os usuários marcados como administradores no cadastro de usuários padrão do webrun. Como o filtro é fixo, não é necessário fazer nada além de definir a consulta na grade, e, ao clicar no botão atualizar, o operador pode obter informações em tempo real. Note que nesta grade apenas o botão atualizar está disponível, pois, trata-se de uma consulta apenas para visualização. (veja Definições do Formulário aqui)

Figura 3 – Exemplo de Consulta simples

Ainda no contexto de consultas, é importante ressaltar a seguinte questão: o formulário que vai popular a grade com os resultados da consulta na maioria dos casos vai necessitar de apenas alguns campos, por exemplo, veja a consulta da Figura 3. São exibidas apenas as colunas: Código, Login e Email do usuário. Esta grade está editável, por isto, todos os campos que estiverem no formulário detalhe serão exibidos na ordem da tabulação. Nos casos de grades não editáveis, como na Figura 2, escolhe-se as colunas que se deseja exibir, porém, se um mesmo campo aparecer mais de uma vez no mesmo formulário, como em cabeçalhos nas abas, ele vai se repetir na grade, o que não é desejável. Por estes motivos, é que se deve sempre criar uma nova tela específica para a grade, uma vez que, associar a mesma tela à qual se dá manutenção nos registros pode provocar efeitos inconvenientes como repetição de colunas, ou colunas com espaçamento muito grande, devido ao layout da tela base. Entre escolher o layout da tela de manutenção e o layout da grade de consulta, escolha criar outra tela específica para a consulta. Sobre isto, você pode dizer: “Mas eu gostaria que quando o usuário clicasse duas vezes no registro, o formulário de cadastro abrisse para edição ou visualização”. Isto pode ser feito via fluxo no evento Ao Duplo Clicar da grade, ou, uma solução mais prática é adicionar um botão no formulário da grade chamando o formulário de manutenção dos registros, passando a chave primária do mesmo como parâmetro, como mostra a Figura 3.

Existem ainda situações onde é útil fazer uma consulta para fins de atualização de registros, por exemplo, em um sistema de vendas, por conta de algum tipo de falha, pode ser necessário consultar os pedidos que estão com data de vencimento entrega à data de emissão, portanto, se faz necessário criar uma tela onde se visualize estes registros e, na mesma tela, deve ser permitido corrigir estas datas. Para tal, use a mesma solução citada no parágrafo anterior, mas, tornando os botões alterar e gravar disponíveis e mude os campos que não se deseja alterar para somente leitura, como mostra a Figura 4.

Figura 4 – Exemplo de Consulta com atualização de registros

Termina aqui a série de posts sobre Boas Práticas com o Maker. Este post assim como os demais não tem a pretensão de ser um guia definitivo, mas, servir de base para aqueles que estão iniciando com o Maker e não se depararam ainda com situações o suficiente para tomar decisões de projeto nessa nova forma de desenvolver sistemas. Poderíamos aprofundar bastante o assunto sobre formulários, falando de abertura de formulários em moldura, criação de componentes dinamicamente, dentre outros. Mas, fica aqui a promessa de que estes assuntos serão abordados futuramente com maior amplitude. Até a próxima!

Atualização Remota de Sistemas em Maker


Uma etapa importante do processo de desenvolvimento de sistemas é o deploy, ou a instalação do sistema no servidor de aplicações, para uso por parte do cliente. No caso do Maker, a forma como o deploy é feito tem impacto direto na forma como as atualizações serão distribuídas. Caso a aplicação seja distribuída por meio de .war, a atualização no cliente se dá por meio de substituição do .war de produção. Caso a aplicação seja distribuída para o cliente com o webrun e com o banco de dados completo, ou seja, com os fontes do Maker (fr_formulario, fr_componente, etc), é possível atualizar o sistema através de acesso remoto e importação de .frz. Neste post falarei como otimizar a atualização dos sistemas para o último caso.

Acesso via VPN

Para atualizar o Maker através de acesso remoto, é necessário que o servidor onde o banco de dados da aplicação se encontra esteja acessível via IP. Se o BD estiver em um domínio da Web, basta acessá-lo diretamente, caso contrário, faz-se necessário o uso de um software que estabeleça uma VPN (Virtual Private Network) entre a máquina do desenvolvedor e o servidor, como mostra a figura abaixo. Dentre os softwares para tal finalidade estão: LogMeIn Hamachi, TeamViewer,  dentre outros. Cada um deles tem uma forma de configurar a VPN, no caso do hamachi, basta criar uma rede (definindo nome e senha de acesso) e incluir cada estação nesta rede.

Figura 1 – Diagrama de rede com conexão via VPN entre duas redes locais

 

Uma vez estabelecida a VPN, basta criar um novo projeto no Maker, e no campo servidor, informar o IP da base de dados remota, como mostra a Figura 2. Após configurar o projeto, você vai ter acesso a todos os artefatos (formulários, fluxos e relatórios) diretamente pelo Maker, sendo que, qualquer alteração feita irá necessitar entrar em modo projeto na tela modificada e recarregá-la com ctrl+f5, ou reiniciar o sistema. O mais prático é entrar em modo projeto e recarregar a tela, já que isso precisa ser feito uma única vez, depois disto qualquer usuário que abrir a mesma tela já verá o conteúdo atualizado. Ainda assim, existem casos onde o cliente necessita limpar o cache do sistema.  Lógico que as alterações não precisam ser feitas direto no banco remoto, mas, num caso de atualização urgente, esse mecanismo se faz eficiente. O ideal para este tipo de conexão seria realizar alterações no projeto no banco de testes e importar o .frz com as alterações desejados no banco de produção, como mostra a Figura 3. De toda forma, fazer alterações desta forma é mais transparente para o cliente, que basta recarregar um formulário, executar um fluxo ou emitir um relatório para vê-lo atualizado.

Figura 2 – Criação de novo projeto em servidor remoto

Figura 3 – Modelo de manutenção de sistemas em Maker

 

O ponto negativo dessa abordagem é a lentidão na atualização dos sistemas, como a conexão é pela internet, a velocidade de gravação dos artefatos no Maker pode ser muito lenta, pois, até a versão 2.5.1.55, quando se alterava um formulário, fluxo ou relatório no Maker, não importava se era uma alteração complexa, ou se era a mudança de uma única propriedade, o tempo de gravação era o mesmo, o que implica dizer que todas a propriedades do artefato em questão eram regravadas no banco de forma integral. A importação de .frz é igualmente lenta, quando se trata de formulários com muitos componentes ou relatórios. Por conta disto, o ideal, tratando-se de alterações em um servidor remoto, seria utilizar o Maker rodando direto no servidor onde o banco se encontra, e é disto que fala o próximo tópico deste post.

Acesso Remoto

Para evitar o tráfego de informações pela internet no momento de salvar artefatos no Maker remotamente é possível lançar mão de alguns softwares para editar o sistema diretamente no servidor remoto. Entretanto, para que o Maker possa ser aberto é necessário que o hardlock (token) esteja conectado à máquina em questão. Caso sua empresa atenda diversos clientes, é inviável financeiramente adquirir um novo hardlock para cada novo cliente. Para este fim, pode-se utilizar o software USB over Network, este software é disponibilizado em duas versões, cliente e servidor, seu propósito é possibilitar que uma máquina compartilhe um dispositivo USB qualquer com outras máquinas na mesma rede (local, via internet ou VPN). Para tal, é necessário instalar o USB over Network Server na máquina que possui o token conectado, e instalar o USB over Network Client no servidor onde o BD do sistema Maker se encontra. Neste passo, instale o TightVNC nas duas estações, software para acesso remoto, é importante que seja este programa, pois com outros acessos remotos, como o Remote Desktop Connection (nativo do Windows) ou o TeamViewer, a conexão USB remota simplesmente não funciona! O TightVNC também é dividido em server e client, neste caso, o server deve ser a máquina que será acessada, o servidor de BD remoto.

Após fazer a instalação, abra o USB over Network Server, clique no dispositivo que representa o token, de nome ‘Safenet Inc. Safenet Sentinel’ e clique no botão ‘Share’, como mostra a Figura 4-a. Agora, abra o cliente TightVNC e se conecte à estação servidor, uma vez conectado, abra o USB over Network Client, adicione o servidor USB utilizando o endereço IP da máquina onde o token está conectado (no caso da VPN, é o IP gerado pelo Hamachi ou TeamViewer), clique no dispositivo USB de nome ‘Safenet …’ e em seguida clique em ‘Connect USB Device’, como mostra a Figura 4-b. Feito, isto, abra o Maker e utilize-o normalmente! Cabe aqui dizer que, o token só poderá ser utilizado em uma única estação por vez, uma vez que você compartilha o token que está plugado em sua máquina, você não mais o possui, sendo que, para abrir o Maker localmente, você precisará interromper o compartilhamento.

Figura 4 – Utilização do USB over Network

Existem algumas queixas a respeito do desempenho do TightVNC, já que ele não é tão rápido quanto o serviço de acesso remoto nativo da Microsoft. Entretanto, o TightVNC é necessário apenas para fazer a conexão com o dispositivo USB, uma vez que a conexão esteja realizada, o TightVNC pode ser fechado, pois a sessão do usuário continuará aberta na estação remota. Daí em diante pode-se utilizar outro acesso remoto com o qual se possa fazer logon e logoff, como o serviço nativo da Microsoft, que tem desempenho melhor do que os demais.

Com esta solução, os problemas de demora para salvar e importar .frz, apresentadas pela solução do tópico anterior, são resolvidos e é possível realizar alterações remotamente em tempo real seja diretamente no BD de produção, seja via importação de .frz.

 

Alterando a Interface Padrão do Webrun – Barra de Navegação Vertical


Para aqueles que estão iniciando no Maker, algumas atividades tais como: adicionar bibliotecas externas (veja este post) e mudar a interface padrão parecem desafios maiores do que o que realmente são. Quem acompanha o grupo de usuário GUMAKER sabe que diversos usuários já conseguiram modificar a interface padrão, seja com o pacote de skins disponibilizado pela Softwell, seja mudando as imagens do skin padrão, seja criando novas interfaces manualmente e linkando ao conjunto de servlets do webrun, responsáveis pela abertura de formulários, acesso ao banco, execução de regras, emissão de relatórios, etc. Para desmistificar um pouco essa questão da possibilidade de alterar a interface padrão do webrun, farei uma série de postagens neste sentido.

Este post irá mostrar de forma completa como mudar a barra de navegação das telas do webrun, da posição horizontal, para a posição vertical, e como fazer os ajustes necessários para que o layout não fique ‘quebrado’ por conta disto. Na figura abaixo é possível visualizar o resultado esperado:

Figura 1 – Formulário no webrun com barra de navegação Vertical.

O primeiro passo para realizar esta alteração é entender o funcionamento da barra de navegação do webrun, como os objetos são construídos e quais são os métodos envolvidos. Para tal, vá até a pasta de deploy do tomcat onde as definições dos componentes ficam armazenadas: ‘.\Maker 2.X\Webrun 2\tomcat\webapps\webrun\components\’. Neste diretório iremos analisar três arquivos:

  • ‘HTMLNavigation.js’ – arquivo que define classe de mesmo nome. Trata-se de uma classe básica que define o comportamento visual para o controla da navegação.
  • ‘HTMLNavigationForm.js’ – arquivo que define classe de mesmo nome. Esta classe herda de HTMLNavigation, agregando funcionalidades específicas para exibição da barra de navegação no formulário, a exemplo de: definição dos ícones a serem utilizados, associação de ações aos botões.
  • ‘HTMLTab.js’ – arquivo que define classe HTMLTabController. Trata-se de uma classe responsável por controlar as ações e o comportamento da área onde os componentes são exibidos, possui funções que realizam tarefas tais como: adicionar aba, adicionar aba localizar, capturar eventos de clique na área do formulário, etc.

Além dos arquivos descritos acima existe o ‘HTMLNavigationGrid.js’, responsável pela definição do comportamento dos botões de navegação do componente grade, cujo conteúdo não é diretamente relevante para o que será descrito aqui.

Analisando o código fonte de um formulário aberto no webrun, é possível verificar que um objeto HTMLNavigationForm é inicializado com o trecho de código abaixo:

d.n = new HTMLNavigationForm(‘MEX’, 202376796, 2, 3);
d.n.setMainImages(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1);
d.n.setEditImages(1, 1);
d.n.setIncludeImages(1, 1);

As chamadas acima fazem com que a barra de navegação e os botões sejam criados, de acordo com as definições do formulário. Cada parâmetro dos métodos setMainImages(),setEditImages()setIncludeImages(), indicam se um botão irá aparecer ou não, para mais detalhes, veja o código do arquivo ‘HTMLNavigationForm.js’. Estes métodos invocam respectivamente os métodos addMainButton()addEditButton()addIncludeButton(), que pertencem à classe HTMLNavigation.

A seguir será mostrado onde e como alterar cada arquivo .js que afeta a solução aqui proposta. É importante fazer um backup desses arquivos antes, para uma futura restauração dos componentes originais. Neste exemplo, os arquivos a serem substituídos foram criados na pasta ‘Webrun 2/Maker.Commons/’, sendo que, é necessário reiniciar o webrun a cada alteração. É possível também alterar os arquivos diretos na pasta de deploy, mas os mesmos seria perdidos caso haja uma republicação do webrun, criá-los em Maker.Commons ajuda a deixar organizada a solução, sendo que, quando ela não for mais desejada, ou quando outra solução for colocada em produção, basta substituir os arquivos sem risco de perdê-los.

Alterando o arquivo ‘HTMLNavigation.js’

Abra o arquivo ‘HTMLNavigation.js’ e analise o método addMainButton(), abaixo:

 HTMLNavigation.prototype.addMainButton = function(img, hint, onclick, width, tab) {
  var bt = this.createButton(img, '', hint, onclick, this.posMain, this.div, width, tab, true);
  this.posMain += width + 1;
  this.manButtons.push(bt);
  return bt;
}

Para cada chamada à função acima a partir do método setMainImages() da classe HTMLNavigationForm é criado um novo botão, através da chamada ao método createButton(), sendo que o seu quinto parâmetro de nome space recebe a posição absoluta do botão no sentido horizontal (em termos de HTML, é o atributo left, distância da margem esquerda) por meio do atributo posMain. Este atributo é incrementado com o valor da largura do botão, e, desta forma, todos os botões são dispostos horizontalmente. A primeira alteração a ser feita no sentido de mudar a orientação da barra de navegação para exibição vertical dos botões é alterar o método createButton(), este método cria um objeto HTMLImageButton, passando por parâmetro a distância da margem esquerda, mas, olhando o construtor deste objeto, é possível perceber que o mesmo também recebe a distância do topo (coordenada vertical), que por sua vez é ignorada. Desta forma, basta adicionar um parâmetro à função createButton() e informar este valor ao construtor da classe HTMLImageButton, veja o trecho de código abaixo:

 /* Trecho de código original
HTMLNavigation.prototype.createButton = function(img, description, hint, onclick, space, div, width, tab, visible) {
  var bt = new HTMLImageButton(this.sys, this.formID, -1, 0, space, width, this.height, hint, img);
  {...}
  } */
   /* Início do trecho de código modificado */
HTMLNavigation.prototype.createButton = function(img, description, hint, onclick, spaceX, spaceY, div, width, tab, visible) {
  var bt = new HTMLImageButton(this.sys, this.formID, -1, spaceX, spaceY, width, this.height, hint, img);
  {...}
  }
  /* Fim do trecho de código modificado */

O parâmetro space passou a se chamar spaceX e foi criado o parâmetro spaceY. Com esta alteração, todas as chamadas ao método createButton() deverão ser alteradas, caso contrário todos os parâmetros após space irão receber um valor incorreto, o que provocará erros. A intenção de tal alteração é parametrizar a disposição dos botões na barra de navegação, para isto será criado um atributo na classe HTMLNavigation chamado orientation que possuirá os valores ‘hor’ ou ‘ver’. Também será adicionado outro atributo chamado fixedHeight, que irá armazenar a altura dos botões. Estes atributos deverão ser adicionados no método create, veja o trecho de código abaixo:

 HTMLNavigation.prototype.create = function(sys, formID, posX, posY, width, height) {
{…}
/* Início do trecho de código modificado */
  this.orientation = 'hor';
  this.fixedHeight = 0;
/* Fim do trecho de código modificado */
}

Feito isto, é necessário alterar os métodos addMainButton()addEditButton()addIncludeButton(), para que se cheque o valor do atributo orientation a fim de criar a barra de navegação horizontal ou vertical. O método addMainButton() deve ficar como mostra o trecho de código, faça a mesma alteração para os outros dois métodos:

HTMLNavigation.prototype.addMainButton = function(img, hint, onclick, width, tab) {
/* Trecho de código original
  var bt = this.createButton(img, '', hint, onclick, this.posMain, this.div, width, tab, true);
  this.posMain += width + 1;
*/
/* Início trecho de código novo */
  if (this.orientation == 'hor'){
    var bt = this.createButton(img, '', hint, onclick, this.posMain, 0, this.div, width, tab, true);
    this.posMain += width + 1;
}
  if (this.orientation == 'ver'){
    var bt = this.createButton(img, '', hint, onclick, 0, this.posMain, this.div, width, tab, true);
    this.posMain += this.fixedHeight + 1;
}
/* Fim trecho de código novo */
  this.manButtons.push(bt);
  return bt;
}

Observe que a depender do valor do atributo orientation, a chamada ao método createButton() passa o valor do atributo posMain como parâmetro para spaceX ou spaceY. Feito isto, o arquivo ‘HTMLNavigation.js’ está pronto.

Alterando o arquivo ‘HTMLNavigationForm.js’

Agora é necessário alterar o arquivo ‘HTMLNavigationForm.js’, para que a orientação desejada seja definida e a altura dos botões seja informada. É preciso definir aqui um valor para o atributo fixedHeight (definido na superclasse), que vai definir a distância entre cada botão no sentido vertical. Altere este valor para 34, que é o valor da altura e da largura das imagens do skin padrão, veja em ‘webrun/Skins/mainnav_include.gif . Altere o construtor desta classe como mostra o trecho de código abaixo:

 function HTMLNavigationForm(sys, formID, posX, posY) {
  this.create(sys, formID, posX, posY, 34, 34);
/* Início trecho de código novo */
  this.orientation = 'ver'
  this.fixedHeight = 34;
/* Fim trecho de código novo */
}

Como os botões ficarão no sentido vertical, é necessário alterar também o tamanho dos botões Gravar, Gravar+ e Cancelar, pois eles são mais largos do que os demais, se ficarem muito grandes estes botões irão ocupar uma parte da área onde estão os componentes, o que não é desejável. Para tal alteração, abra o arquivo acima mencionado e altere os métodos setEditImages() e setIncludeImages(), como mostra o trecho de código abaixo:

 HTMLNavigationForm.prototype.setEditImages = function(imgSave, imgCancel) {

/* Trecho de código original
  var imgSaveWidth = 80;
  var imgCancelWidth = 80;
*/
 /* Início trecho de código novo */
  var imgSaveWidth = 34;
  var imgCancelWidth = 34;
/* Fim trecho de código novo */
{...}

 }

Após realizar estas alterações, um formulário aberto no maker deverá aparecer como mostra a figura abaixo:

Figura 2 – Formulário com barra de navegação ‘escondida’.

Não é o resultado esperado, não é? O que aconteceu foi que a área de exibição dos componentes, que é a área delimitada por uma aba, está posicionada por cima dos botões, utilizando o firebug no Firefox, para inspecionar o código HTML da página é possível ‘visualizar’ que os botões foram criados corretamente, porém, para correta visualização dos mesmos, é necessário modificar o posicionamento do conteúdo do formulário.

Alterando o arquivo ‘HTMLTab.js’

Este arquivo define a classe HTMLTabController, responsável por desenhar as abas de um formulário. Esta classe possui os atributos posXposY, que definem o posicionamento das abas na tela. Os valores passados a estes atributos são definidos internamente pelo webrun, como é possível perceber analisando o código fonte de um formulário qualquer, veja trecho de código abaixo:

 /* assinatura do construtor da class HTMLTrabController*/
function HTMLTabController(sys, formID, posX, posY, width, height, hideTab) {
 /* código fonte de um formulário */
/* criação de um novo objeto HTMLTrabController */
  d.t = new HTMLTabController('MEX', 202376796, 0, 42, 663, 593, false);

Para que a criação das abas fique da forma como desejamos para este exemplo, é necessário redefinir os valores dos atributos posX e posY, como mostra o trecho de código abaixo:

 function HTMLTabController(sys, formID, posX, posY, width, height, hideTab) {
{…}
/* Trecho de código original
  this.posX = posX;
  this.posY = posY;
*/
 /* Início de trecho de código novo */
  this.posX = 34;
  this.posY = 0;
/* Fim de trecho de código novo */
  {…}
 }

Feito isto, um formulário aberto no webrun deverá ficar da forma como mostra a figura abaixo:

Figura 3 – Formulário com barra de navegação vertical ‘cortando’ a tela.

Está feito, o resultado desejado foi alcançado, os botões da barra de navegação estão dispostos verticalmente! Porém, ao deslocar o posicionamento das abas 34 pixels à direita, a extremidade direita do formulário ficou ‘cortada’. Para que não seja necessário alterar todas as telas do seu sistema para se adequar à nova formatação da barra de navegação, é possível alterar as chamadas aos formulários do maker e acrescentar-lhes 34 pixels na largura.

Alterando o arquivo ‘wfr.js’

Para obter o resultado desejado, é necessário alterar a função openForm() no arquivo wfr.js. Esta função recebe um objeto properties, que contém todas as propriedades necessárias para a abertura de um formulário, analisando o código fonte do formulário principal do webrun é possível visualizar a chamada a essa função e a passagem de parâmetros. Como o objetivo aqui é apenas aumentar a largura de qualquer formulário aberto, adicione o seguinte trecho de código:

 function openForm(properties) {
/* Início trecho de código novo */
  properties.width+=34
/* Fim trecho de código novo */
  {...}
}

Após realizar esta alteração, está pronto!

Esta solução não é a mais elegante que se poderia desenvolver, mas, é válida a título de exemplo. Um desenvolvedor cuidadoso pode pensar em formas de parametrizar os comportamentos desejados pelos componentes visuais do maker, para assim criar mecanismos eficientes para alterar a interface padrão. Ideal seria se houvesse um suporte a plugins, enquanto não há, resolve-se de outras maneiras, como a que foi esboçada neste post. Até a próxima!

Criando um Componente Gráfico baseado em Flot no Maker /Webrun


Neste post falarei como utilizar o Flot para criar um componente novo no Maker. O objetivo aqui não é fornecer uma API completa para utilização, e sim, fornecer um exemplo didático e útil do uso de bibliotecas externas para criação de novos componentes no Maker. O Flot é uma biblioteca para exibição de gráficos feita em Javascript, utiliza jquery e é mantida pelo Google. Clique aqui para mais detalhes.

Para realizar a tarefa aqui proposta, é necessário que o desenvolvedor saiba como referenciar e chamar uma biblioteca Javascript no Maker, para isto existe um tópico na documentação online do Maker, veja aqui.

De posse desses conhecimentos, baixe o .zip do flot neste link e descompacte-o em uma pasta qualquer. Após descompactar, os fontes do Flot poderão ser analisados, leia o arquivo API.txt para entender como utilizar a biblioteca, para este exemplo, não é necessário ler tudo, apenas utilize-o como referência. Crie um diretório chamado Flot, na pasta ‘Webrun2.x/Maker.Commons/’ e copie para lá os arquivos descompactados, é importante que seja neste diretório, pois o seu conteúdo será carregado automaticamente no contexto do webrun ao se reiniciar o tomcat. E, no momento da carga das bibliotecas, iremos referenciar este diretório.

Neste post, mostrarei como criar um gráfico com seleção no webrun. O componente criado permitirá ao usuário disparar dois eventos: 1) selecionar uma região ao longo do eixo X e disparar um fluxo passando por parâmetro os valores x1 e x2 que definem o intervalo; 2) Ao clicar na legenda, o conteúdo do item clicado é passado por parâmetro para um fluxo. O resultado final deverá ser como mostrado na figura abaixo. Cabe dizer que o componente que se pretende desenvolver aqui não será como os componentes nativos, pois não há como criar plugins para o Maker para permitir a configuração visual das propriedades de componentes personalizados , entretanto, é possível fazê-lo de forma simples, utilizando o componente do tipo Moldura para definir o tamanho do nosso componente personalizado e utilizando um fluxo como interface para passagem de dados para as funções Javascript. Este procedimento será explicado de forma completa em 4 passos.

Figura 1 – Exemplo de gráfico com seleção rodando no Webrun

1º passo – Definir o componente Javascript

Neste passo, é preciso compreender o exemplo do Flot e criar o componente Javascript. Abra o código fonte do arquivo ‘examples/selection.html’ em seu editor de textos ou IDE de preferência, aqui utilizo o Notepad++, que fornece uma identação que julgo suficiente para se desenvolver em Javascript. Neste arquivo é possível perceber três ações importantes: 1) Importação de bibliotecas; 2) Definição dos dados; 3) Criação e utilização dos objetos Flot. São estas as mesmas ações que realizaremos aqui com o fim de criar um componente para o Maker.

Para começar o trabalho, crie um diretório qualquer para armazenar seu componente, é interessante que seja em algum diretório visível pelo servidor, como o ‘Webrun2.x/Maker.Commons’. Em seguida, crie um novo arquivo de texto, na IDE escolhida, e lhe dê o nome de ‘flotSelection.js’. Neste arquivo, iremos criar nosso componente, onde iremos definir uma classe com seus atributos e métodos. Além disso, este .js conterá funções simples para criação e utilização de um objeto da classe definida. Como referência, vamos utilizar o componente ‘Caixa de Texto’ do Maker, cujo código fonte está disponível em: ‘webrun/componentes/HTMLEdit.js’. Neste ponto é interessante que se tenha conhecimentos sobre Orientação a Objetos com Javascript. Uma boa referência sobre este assunto encontra-se aqui.

O nome do nosso componente será HTMLFlot, ele possuirá os seguintes atributos:

  • Sigla do sistema;
  • ID do formulário;
  • Nome do objeto moldura;
  • Regra a ser chamada ao selecionar região no gráfico;
  • Regra a ser chamada ao de-selecionar região no gráfico;
  • Regra a ser chamada ao clicar na legenda.

E possuirá os seguintes métodos:

  • Inicializar objetos e carregar bibliotecas;
  • Definir dados;
  • Definir opções;
  • Associar eventos;
  • Plotar gráfico.

A definição em Javascript do componente acima descrito pode ser vista abaixo:

// Definição do componente gráfico Flot

function HTMLFlot(sys, formID, canvas, onSelectRuleName, onUnSelectRuleName, onClickLegend) {
this.sys = sys
this.formID = formID
this.canvas = canvas
this.onSelectRuleName = onSelectRuleName
this.onUnSelectRuleName = onUnSelectRuleName
this.onClickLegend = onClickLegend
try
{
length = $mainform().document.HTMLFlotList.length
} catch (e)
{
$mainform().document.HTMLFlotList = new Array();
}
$mainform().document.HTMLFlotList[canvas] = this;
}

HTMLFlot.prototype.init = function()
{
var url = getPath($mainform().location)
webrun.include(url+’flot/jquery.js’)
webrun.include(url+’flot/jquery.flot.js’)
webrun.include(url+’flot/jquery.flot.selection_webrun.js’)
webrun.include(url+’flot/jquery.flot.crosshair.js’)
var componentCanvas = $controller().getElementById(this.canvas, this.formID).div
componentCanvas.setAttribute(“id”, this.canvas)
}
HTMLFlot.prototype.setData = function(data){
this.data = data
}

HTMLFlot.prototype.setOptions = function(options){
this.options = options
}

HTMLFlot.prototype.plot = function()
{
this.plot = $.plot(this.placeholder, this.data, this.options);
}

HTMLFlot.prototype.setRules = function()
{
this.placeholder = $(“#”+this.canvas, $mainform().document);
this.placeholder.bind(“plotselected”, function (event, ranges) {
flotObj = $mainform().document.HTMLFlotList[this.getAttribute('id')]
if (flotObj.onSelectRuleName != ”){
var params = [];
params.push((new Date(ranges.xaxis.from)).toString());
params.push((new Date(ranges.xaxis.to)).toString());
return executeJSRule2(flotObj.sys, flotObj.formID, reduceVariable(flotObj.onSelectRuleName), params, false, ”);
}
});

this.placeholder.bind(“plotunselected”, function (event) {
if (this.onUnSelectRuleName != ”){
return executeJSRule2(this.sys, this.formID, reduceVariable(this.onUnSelectRuleName), [], false, ”);
}
});

$mainform().document.getLegendClicked = function (legenda, id) {
var flotObj = $mainform().document.HTMLFlotList[id]
var params = []
params.push(legenda);
return executeJSRule2(flotObj.sys, flotObj.formID, reduceVariable(flotObj.onClickLegend), params, false, ”);
}
}

// Definição de função para executar fluxo cliente
function executeJSRule2(sysId, formId, funcao, params, throwErrors, extraParams) {
if (!throwErrors)
$mainform().document.hasRuleErrors = false;
var paramQryStr = new Array();
var position = 0;
if (params instanceof Array && params.length > 0) {
for (; position < params.length; position++) {
if (params[position]) {
var value = params[position];
var isObject = (typeof value == ‘object’);
if (isObject && value) {
value = value.value;
}
var isLiteral = (typeof value == ‘string’);
if (!isLiteral) {
if (value) {
value = eval(“document.c_” + value + “.getValue()”);
} else {
value = “”;
}
}
paramQryStr[position] = value;
} else {
paramQryStr[position] = null;
}
}
}
position = -1;
if (extraParams && extraParams.length > 0) {
for (var i = 0; i < extraParams.length; i++) {
if (typeof(extraParams[i]) != ‘object’ && typeof(extraParams[i]) != ‘undefined’) {
position++;
paramQryStr[position] = extraParams[i];
}
}
}
var func = $mainform().eval(funcao);
var ruleInstance = new func(null, sysId, formId);
if (throwErrors) {
return ruleInstance.run.apply(ruleInstance, paramQryStr);
} else {
try {
/*
* Meio alternativo de sobrepor um problema no firefox.
* Ele estava perdendo a referência de parent.mainform quando cliente chamava java.
*/
parent.mainform;
return ruleInstance.run.apply(ruleInstance, paramQryStr);
} catch(ex) {
handleException(ex);
}
}
}

É importante explicar a criação da função executeJSRule2(). No pacote wfr.js existe a função executeJSRule() que realiza a chamada a um fluxo cliente do Maker. Foi necessário definir essa função, de código idêntico à função original, pois no contexto em que a mesma é executada, ou seja, a partir de um fluxo servidor que lê um arquivo e o executa com a função ‘Executar Javascript’, o objeto necessário para rodar a função eval() não é encontrado, sendo necessário alterar a linha de código para $mainform().eval(), sendo que $mainform() é uma função definida em wfr.js que retorna o objeto document do frame no qual o formulário em questão é carregado. Esta linha está destacada em vermelho no trecho de código acima. Da mesma forma, observe na função init(), que é carregada uma biblioteca modificada, de nome ‘jquery.flot.selection_webrun.js’, na função init() do objeto definido por esta biblioteca, foi necessário alterar para que fosse obtido o objeto correto, em situação semelhante a que foi explicada anteriormente para a função executeJSRule2() , sendo necessário trocar as ocorrências do objeto document por $mainform().document. Este procedimento é essencial para o funcionamento do exemplo aqui apresentado!

Com o objeto definido, se faz necessário criar funções para utilizá-los, essas funções servirão apenas de interface com o objeto, elas poderão ser criadas como funções no Maker, mas, para fins de exemplo, eu preferi manter em código, pois é mais simples de mudar e testar, visto que alterar funções criadas no Maker requer reiniciar webrun e isso não é desejável enquanto se está testando. Caso queira criar funções no Maker, veja neste link da documentação online.

As funções a serem definidas são:

  • Criar novo objeto Flot
  • Configurar Gráfico
  • Plotar Gráfico

O código Javascript dessas funções pode ser visto abaixo:

// Definição de funções para chamada ao objeto Flot
function ebfFlotCreateNewSelectionChart(sys, formID, canvas, onSelectRuleName, onUnSelectRuleName, onClickLegend)
{
var flot = new HTMLFlot(sys,formID, canvas, onSelectRuleName, onUnSelectRuleName, onClickLegend)
flot.init();
return flot;
}

function ebfFlotConfigChart(flot, data, options)
{
flot.setData(data)
flot.setOptions(options)
flot.setRules()
}

function ebfFlotPlotChart(flot)
{
flot.plot()
}

Feito isto, o arquivo flotSelection.js está finalizado e pronto para uso.

2º Passo – Criar o arquivo .js que fará interface com o fluxo

Neste passo, iremos criar um arquivo chamado callFlot.js que irá obter parâmetros definidos em fluxo e chamar as funções definidas acima: criar novo objeto, configurar gráfico e plotar gráfico. Neste link da documentação do Maker citado anteriormente mostra-se como se faz para obter dados do fluxo a partir de um código Javascript chamado pela função ‘Executar Javascript’. Segue abaixo trecho de código que obtém os parâmetros e realiza chamadas às funções:

var sys = $mainform().document.WFRForm.sys.value
var formID = $mainform().document.WFRForm.formID.value
var canvas = <%moldura%>;
var onSelectRuleName = <%fluxo – ao selecionar região%>;
var onUnSelectRuleName = <%fluxo – ao de-selecionar seleção%>;
var onClickLegend = <%fluxo – ao clicar na legenda%>;
var data = eval(<%dados%>)
var options = {
series: {
lines: { show: true },
points: { show: true },
clickable: true,
},
legend: { noColumns: 4,
labelFormatter: function(label, series) {
// series is the series object for the label
return ‘<a onClick=”$mainform().document.getLegendClicked(\”+label.replace(‘\\’, ‘\\\\’)+’\', \”+canvas+’\');” href=”javascript:void(0);”>’ + label + ‘</a>’;
}
},
crosshair: { mode: “x” },
//xaxis: { tickDecimals: 5 },
xaxis: { mode: “time”,  timeformat: “%d/%m/%y”},
yaxis: {
tickFormatter: function(val, axis){
num = val.toString().replace(/\$|\,/g,”);
if(isNaN(num))
num = “0″;
sign = (num == (num = Math.abs(num)));
num = Math.floor(num*100+0.50000000001);
cents = num%100;
num = Math.floor(num/100).toString();
if(cents<10)
cents = “0″ + cents;
for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
num = num.substring(0,num.length-(4*i+3))+’,'+
num.substring(num.length-(4*i+3));
return (((sign)?”:’-') + ‘R$’ + num + ‘.’ + cents);
}
},
selection: { mode: “x” },
grid: {
backgroundColor: { colors: ["#fff", "#eee"] }
}
};

var flot = ebfFlotCreateNewSelectionChart(sys, formID,canvas, onSelectRuleName, onUnSelectRuleName, onClickLegend)
ebfFlotConfigChart(flot,data,options)
ebfFlotPlotChart(flot)

O formato das variáveis data e options precisam estar de acordo com a notação JSON, veja no arquivo de exemplo do flot, ‘examples/selection.html’. Na figura 2 é possível visualizar um fluxo que retorna os dados no formato requerido pela API do Flot. Neste exemplo, para simplificar, as opções foram definidas em código Javascript mesmo, como pode ser visto no trecho de código acima. Para alterar as opções de plotagem, consulte a documentação da API do flot, neste exemplo, as opções foram feitas para exibição de um gráfico de valores monetários por data. Repare que na definição das opções de legenda é definida uma função Javascript que irá chamar a função $mainform().document.getLegendClicked(), definida no arquivo ‘flotSelection.js’ criado no 1º passo deste post. Este evento não é disponibilizado pela API do Flot, sendo criado desta forma para incrementar as funcionalidades da solução aqui apresentada.

Figura 2 – Fluxo que retorna os dados no formato JSON

3º Passo – Criar o Fluxo principal

Neste passo, criaremos um fluxo que irá definir os parâmetros necessários para a criação do gráfico e um fluxo para obtenção dos dados. Para tal, basta criar um fluxo e definir as variáveis com os mesmos nomes que foram informados no arquivo ‘callFlot.js’, como mostra a figura abaixo. O fluxo ‘FLOT – Obter Dados’, retorna os dados no formato JSON, citado no passo anterior, na Figura 3 é possível visualizar também a chamada à função Executar Javascript, que, carrega os dois arquivos .js criados nos passos 1 e 2 e os executa numa mesma chamada, trata-se de um fluxo servidor. Da forma como o componente aqui desenvolvido foi projetado, é necessário realizar uma única chamada que execute todo o código Javascript, pois as funções definidas só irão existir dentro do contexto da função Executar Javascript chamada, caso seja desejável utilizar as funções do componente criado mais de uma vez em uma mesma tela, é necessário modificar o código das mesmas, associando-as ao objeto $mainform().

Figura 3 – Fluxo que realiza interface de dados com as funções Javascript

4º Passo – Criar o Formulário

Neste passo, é necessário criar um formulário simples, com um objeto moldura onde o gráfico será exibido. Renomeie este componente para o mesmo nome que você informou na variável moldura no fluxo definido no passo anterior. Para este formulário, será necessário associar o fluxo criado no passo anterior no evento ‘Ao Entrar’ para que o resultado seja contemplado visualmente. Veja abaixo o resultado final e as chamadas aos eventos ‘Ao Selecionar Região’ e ‘Ao Clicar em Legenda’.

Figura 4 - Retorno de fluxo chamado em evento 'Selecionar Região'

Figura 5 - Retorno de fluxo chamado em evento 'Clicar em Legenda'

Está pronto! Agora basta utilizar o componente e explorar suas funcionalidades. É possível, por exemplo, utilizá-lo para filtrar um relatório, através da seleção de período e de um item pela legenda, também é possível utilizar o objeto árvore para filtrar o gráfico e exibir dados específicos, e assim por diante, basta ter criatividade. Até mais!

Boas práticas com o Maker 2/3 – Programação com Fluxo


Este é a segunda parte de uma série de três postagens abordando o tema ‘Boas práticas com o Maker’. Neste post será abordada uma série de práticas que podem ser aplicadas à programação com fluxos com o objetivo de aumentar a produtividade do processo de desenvolvimento com o Maker.

Um ponto importante a ser discutido é a questão da nomenclatura dos fluxos. É importante que se defina um padrão para nomeá-los, principalmente pela flexibilidade que é permitida pelo Maker, como uso de espaços, acentos, cedilha, etc. É permitido ainda que os fluxos sejam categorizados, cada categoria é criada como uma pasta, obedecendo a uma hierarquia. No entanto, a utilização dessas categorias na localização dos fluxos não é muito prática, visto que, na tela principal do maker, essa estrutura de pastas e fluxos é exibida como uma TreeView totalmente expandida, o que de maneira prática equivale a uma grande lista com todos os fluxos. Desta forma, para conseguir localizar um fluxo com esta interface é necessário saber seu nome por completo ou pelo menos parte dele, e utilizar o operador ‘%‘ para tal da seguinte forma: ‘%contendo’ como mostra a Figura 1. À esquerda pode-se ver a lista de fluxos na tela do Maker, e à direita está a lista de fluxos no momento da seleção de um sub-fluxo, o filtro de fluxos pelo nome em ambas se dá da mesma forma.

Figura 1 - Exemplo de localização de fluxos com o uso do operador %

Uma boa prática de nomenclatura dos fluxos é utilizar o modelo ‘Módulo do Sistema’ – ‘Nome da Tela’ – ‘Objetivo do Fluxo’, por exemplo: ‘Vendas – Pedido de Venda – Calcular Total’. Fazendo desta forma, evita-se criar fluxos com nomes repetidos ou muito parecidos, que dificultem a identificação de sua funcionalidade, sendo necessário abri-lo e analisá-lo para saber. Por exemplo, em um sistema comercial, podem existir diversos fluxos chamados ‘Calcular Total’, de modo que se torna indispensável fazer essa distinção pelo nome.

Outra questão a ser discutida é o planejamento do sistema voltado para a criação de fluxos reutilizáveis. Por isto, o conceito de Modularização da programação estruturada deve ser observado e aplicado. É importante que os fluxos criados possuam escopo bem delimitado, para facilitar a manutenção e a utilização destes. Por exemplo, em um sistema de vendas, tem-se um fluxo chamado: ‘Vendas – Pedido de Venda – Calcular Totais’, este fluxo é composto por uma consulta ao banco de dados para obter os totais desejados, gravá-los no banco e atualizá-los na tela. Se, posteriormente, for necessário fazer uma validação qualquer nesta tela, para que não se calcule os totais se o pedido estiver liquidado, é interessante que se crie outro fluxo, chamado: ‘Vendas – Pedido de Venda – Validação’, em vez de fazer a validação no mesmo fluxo que calcula. Isto mantém o sistema organizado, facilitando a manutenção, a detecção de erros e permite a reutilização. Vide Figura 2.

Figura 2. Exemplo de Modularização com Fluxos

No processo de desenvolvimento com o Maker existem regras ou operações que eventualmente vão se repetir nas diversas telas do sistema, como por exemplo: exibir/ocultar componentes, atualizar componentes, habilitar/desabilitar componentes, gravar arquivo em disco, validar email, validar preenchimento de campos, etc. Tome como exemplo um cadastro de pessoa, onde, a depender do tipo da pessoa, física ou jurídica, o sistema necessite exibir os campos corretos de acordo com o tipo selecionado. Veja nas figuras abaixo, três formas de resolver este problema. Na Figura 3, os componentes são exibidos ou ocultados com processamentos independentes, sendo que, para quatro componentes em tela, serão necessários oito processamentos, fazendo desta forma. Na Figura 4, utiliza-se um sub-fluxo que recebe uma lista de componentes por parâmetro, separados por vírgula, e um campo do tipo lógico, então itera-se sobre esta lista, e cada componente é exibido ou ocultado, a depender do valor do campo lógico. Desta forma, utilizando um fluxo genérico, são necessárias apenas quatro sub-fluxos, ou apenas dois se a comparação ‘O Tipo de Pessoa é Física?’ for colocada direto na passagem de parâmetros para o sub-fluxo, como mostra a Figura 5. As soluções apresentadas pelas figuras 4 e 5 podem ser utilizadas para uma quantidade indefinida de componentes com alteração apenas nos parâmetros para os sub-fluxos.

Figura 3 - Exemplo de fluxo para Mostrar/Esconder componentes feito de forma não reutilizável.

Figura 4 - Exemplo de fluxo para Mostrar/Esconder componentes feito de forma reutilizável.

Figura 5 - Exemplo de fluxo para Mostrar/Esconder componentes feito de forma reutilizável e compacta.

A reutilização de fluxos pode-se dar ainda quando se tem um mesmo conjunto de fluxos usado para manipular diversas telas com finalidades próximas e que manipulam os mesmos componentes, fazendo-os, aparecer, desaparecer, efetuar cálculos etc. Por exemplo, considerando um cadastro de pessoa num sistema de vendas, pode ser desejar criar uma tela que só mostre clientes, outra só para fornecedores, outra para transportadoras, etc. Todavia, todas estas telas deverão compartilhar a mesma funcionalidade citada no parágrafo anterior, de exibir/ocultar componentes a depender do tipo da pessoa, física ou jurídica. Desta forma, é útil garantir que os nomes dos componentes sejam iguais nas telas que executam o mesmo fluxo, para que a reutilização seja possível.

Ainda neste contexto, outro exemplo de fluxo útil para promover a reutilização é aquele que retorna o código ou GUID do formulário corrente. Algumas funções precisam do código do formulário para ser executadas, dentre elas as muito utilizadas: “Alterar Valor do Componente“ e “Obter Valor do Componente”. Por isto, no caso de haver necessidade do uso de tais funções em fluxos compartilhados por mais de um formulário é possível criar um fluxo que obtenha o código do formulário corrente, ou seja, o código do formulário a partir do qual o fluxo em execução foi chamado, com a função ‘Obter ID do Formulário’, recebendo como único parâmetro o retorno da função ‘Obter Formulário Atual’, ambas disponíveis nativamente no Maker.

Para finalizar, a produtividade com o Maker pode ser seriamente comprometida se a estrutura da sua aplicação não for planejada de modo que facilite a manutenção/evolução do sistema. A organização dos fluxogramas é parte fundamental desta estrutura, pois são eles que armazenam as regras de negócios agregadas à solução proposta ao cliente. No próximo e último post desta série, que aborda ‘Boas práticas com o Maker’, falaremos sobre o projeto de telas. Até lá!

Boas práticas com o Maker 1/3 – Modelagem de Bancos de Dados


Teoricamente, quem desenvolve sistemas com o Maker não precisa se preocupar com linguagens de programação (exceto se precisar de funcionalidades das quais a ferramenta não dispõe nativamente), Projeto Orientado a Objetos, Hibernate, CSS, Tomcat, javascript … bom, javascript é bom conhecer sim! :)

Todavia, engana-se quem acha que o Maker faz milagres e que não é necessário saber programar e aplicar com profissionalismo as técnicas da programação estruturada. Da mesma forma, quem acha que pode desenvolver um bom sistema, mesmo que seja pequeno, criando tabelas com o wizard do Maker (aquele que sugere a criação de estruturas no banco quando se posiciona componentes numa tela sem campo associado), pode enfrentar sérios problemas. Esta série de postagens, dividida em três partes, visa discutir acerca das boas práticas que se devem adotar nos processos de modelagem de bancos de dados, programação com fluxo e planejamento de telas, neste post daremos ênfase em Bancos de Dados.

Dentre os diversos pontos que podem ser analisados com relação à modelagem do banco de dados deve-se dedicar uma atenção especial no que diz respeito à normalização. A aplicação correta dos conceitos de normalização evita redundâncias nas tabelas, facilitando a manutenção e a integridade dos dados.

Uma boa prática no processo de modelagem de dados é a organização semântica do conteúdo das tabelas. Não é produtivo ter uma tabela com muitos campos (arbitrariamente falando, mais de 50), mesmo que o modelo esteja respeitando as FN’s(Formas Normais). Uma grande quantidade de campos dificulta a identificação e abre margem para ambiguidades, pois podem existir campos com nomes parecidos e finalidades totalmente díspares. Da mesma forma, não é interessante ter tabelas muito parecidas, com parte dos campos em comum, pois acaba provocando retrabalho e replicação de consultas que poderiam ser genéricas.

Por estes motivos, os conceitos de Generalização e Especialização podem ser aplicados de forma a organizar os dados referentes a uma única entidade que contenha muitas informações a ela associadas. Considere como exemplo um sistema de Gestão Escolar, para o qual é preciso cadastrar Funcionários, Alunos e Professores, visto que, essas entidades podem ser generalizadas pela entidade Pessoa, é útil criá-la para armazenar os dados comuns a todas as pessoas, tais como: Nome, CPF, RG, sexo, data de nascimento, etc. Além disto, para armazenar os dados de cada especialização da entidade Pessoa será necessária uma tabela, neste caso, três: Funcionário, Aluno e Professor, cada qual com seus dados específicos.

Entretanto, como contra exemplo, utilizar uma única tabela para armazenar os dados das entidades citadas torna a tabela confusa e de difícil manutenção, pela dificuldade de se reconhecer quais dados dizem respeito a qual entidade, uma vez que a quantidade de campos sempre tende a crescer. Tarefas simples como listar os dados dos alunos pode-se tornar um problema com uma estrutura de tabelas com tais problemas semânticos.

Tratando-se de sistemas que sofrem atualizações sob demanda, essas questões que envolvem a estrutura do modelo de dados são ainda mais críticas, pois nem sempre é possível analisar o modelo com tempo e condições adequadas, devido a pressões do cliente, prazos curtos , urgências ocasionais ou simples desleixo do responsável pelo BD. Por isto é necessário estar atento às questões de modelagem sempre que possível, fazendo reestruturações e ajustes, para que o sistema não só funcione, mas que esteja bem feito e seja de fácil entendimento. O fato de ser possível fazer alterações de forma muito veloz nos sistemas desenvolvidos com o Maker acaba se tornando um fator preocupante, visto que, as questões de projeto podem se tornar secundárias frente ao ímpeto de resolver os pedidos dos clientes com agilidade.

Um mecanismo muito útil para se trabalhar no Maker é o uso de views. Freqüentemente, num sistema, ocorrerá a necessidade de se consultar determinadas informações, em tela, em relatórios e em fluxogramas. Centralizar estas informações numa única view facilita a manutenção, pois basta alterar a consulta da view para que todos os artefatos que a utiliza estejam atualizados, evitando assim que seja necessário realizar uma mesma correção em diversos pontos do sistema, isso se o desenvolvedor lembrar de todos eles! Falando em Maker, a utilização de views desta maneira pode significar que, se um cliente pede uma alteração em um determinado dado de um relatório, basta alterar na view que estará pronto, portanto você não precisará exportar .frz, fazer acesso remoto e alterar o relatório, entrar em modo de projeto, recarregar telas, limpar cache, etc. O ganho de produtividade com técnicas como esta permite que se atenda mais clientes, e que se tenha tempo para se dedicar à estrutura do projeto, principalmente do banco.

Logicamente, a criação das views deve ser um processo bem elaborado, deve-se identificar quais consultas são acessadas em mais de um ponto do sistema, e quais consultas podem servir de base para a realização de outras. Aquelas que realizam cálculos muito pesados devem ser evitadas para não sobrecarregar o banco e congelar os recursos do BD. No caso de haver uma real necessidade de views complexas, é mister elaborar mecanismos para otimizar rotinas, como transações de curta duração e atualizações fragmentadas, que, nos termos do Maker, significa, usar “cliente chamando servidor” (para realizar atualizações muito grandes que travariam o banco) de forma fragmentada, usar a função Executar SQL sem transação, etc.

Para finalizar, não adianta reclamar do Maker sem tentar buscar formas de otimizar o trabalho. Seja qual for a tecnologia, a organização da estrutura do projeto sempre vai impactar de forma crítica a capacidade de mantê-lo e alterá-lo. Como foi dito no começo do tópico, no caso do desenvolvimento ser em Maker, não é necessário se apegar às linguagens, nem aprender diversas tecnologias, mas a qualidade do Banco de Dados e a forma como o mesmo é utilizado é decisiva para o sucesso do projeto. Da mesma forma, a aplicação de práticas conhecidas de programação no ‘fluxo’ e uma boa prototipagem de telas possibilita ao desenvolvedor manter o sistema de forma mais produtiva, mas estes serão temas de outras postagens, até lá.

Exemplo de Grade com Múltipla Escolha


Neste post vou mostrar como desenvolver uma tela com uma grade múltipla escolha no Maker/Webrun, ou seja, uma grade na qual seja possível selecionar diversas linhas, e posteriormente obter as linhas selecionadas e realizar alguma operação com as informações disponíveis. Tomemos como exemplo a tela abaixo:

Figura 1. Tela com grade múltipla escolha, exibindo dados dos usuários.

Nesta tela são exibidos os dados dos usuários cadastrados em um sistema qualquer feito no Maker (tabela FR_USUARIO), sendo possível marcar no checkbox os registros desejados. Ao se clicar no botão ‘Obter Lista de Emails’, é invocado um fluxo que retorna a lista de emails correspondentes às linhas selecionadas. Neste post iremos explicar com detalhes a criação desta tela e do fluxo que realiza o procedimento desejado.

Para começar, vamos analisar a construção da tela. Serão necessários dois formulários, um que será o Formulário Principal, exibido na Figura 1, e o outro será o Formulário Detalhe que irá definir a grade.

O Formulário Principal do exemplo não possui consulta, nem abas, nem barra de navegação, pois não são necessárias para este exemplo, é composto apenas do título da tela, da grade de usuários e do botão ‘Obter Lista de Emails’, vide Figura 2. Um detalhe importante no momento de configurar esta tela é se certificar de que a grade seja editável, para que o campo checkbox apareça e seja clicável.

Figura 2. Formulário Principal – propriedades da grade.

 

O Formulário Detalhe possui uma consulta simples e quatro componentes posicionados na tela, vide Figura 3. O layout aqui não é importante, pois esta tela não irá aparecer para o usuário, entretanto é indispensável configurar a tabulação dos campos, pois isto irá definir a ordem na qual as colunas na grade serão dispostas. É importante ressaltar aqui o detalhe do campo checkbox ‘Marcar?’, ele não precisa ser um campo do banco, mas pode ser caso seja útil armazenar a informação de quais campos foram selecionados. Além disto, o campo checkbox não pode ser uma constante definida na consulta, senão o campo não será clicável na grade, ou provocará algum erro.

Figura 3. Formulário Detalhe

Definidos os formulários, vamos aos fluxos! A questão central no processo de obter a informação que diz se uma determinada linha da grade está com o campo checkbox marcado é analisar o conteúdo deste campo. Fazendo um fluxo que percorra as linhas da grade e obtendo o valor da coluna ‘Marcar?’, os seguintes conteúdos são retornados quando o checkbox estiver:

  • Desmarcado:

    Checkbox desmarcado

  • Marcado:

    Checkbox marcado

  • Nulo:

    Checkbox nulo

É possível perceber analisando o conteúdo retornado, que se trata da definição HTML do componente checkbox. Nesta definição está contida a URL da imagem que representa o checkbox visualmente e um atributo ‘state’. Este atributo pode assumir os valores 0, 1 e 2, representando os estados ‘Desmarcado’, ‘Marcado’ e ‘Nulo’, respectivamente. Sabendo disto, é possível criar um fluxo que receba o conteúdo do checkbox por parâmetro, verifique se existe a subseqüência ‘ state=”1” ’, e retorne true ou false de acordo com a comparação. Este fluxo está exemplificado na Figura 4 a seguir:

Figura 4. Fluxo que verifica se um checkbox em uma grade está marcado.

O fluxo acima ilustrado viabiliza a criação de outro fluxo que percorra as linhas de uma grade e faça a verificação de checkbox marcado em cada linha, armazenando, caso positivo, o valor de uma coluna desejada, como mostra a Figura 5. Este fluxo recebe por parâmetro: nome do campo grade,  nome da coluna que se deseja armazenar, e o nome da coluna do componente checkbox.

Figura 5. Fluxo que obtém os valores desejados nas marcadas com o checkbox

De posse do fluxo acima, voltamos ao nosso Formulário Principal, vide Figura 1. Basta agora associar o fluxo recém-criado ao evento ‘Ao Clicar’ do botão ‘Obter Lista de Emails’, passando os parâmetros necessários, que, neste caso foram: (“MakerGrid1”, “Email”, “Marcar?”). O funcionamento da tela pode ser visto na Figura 6.

 

Figura 6. Formulário principal em funcionamento no webrun.

Está pronto e funcionando!

Este fluxo parametrizado da forma como foi feito permite que esta funcionalidade de múltipla escolha seja explorada de diversas situações com: envio de email para múltiplos usuários, questionário de múltipla escolha, remoção de registros em lote, etc

Se gostou, deixe um comentário com sua opinião. Até o próximo post!

 

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.