sexta-feira, 18 de abril de 2014

Tutorial Table Window – Parte 1 - CRUD

Este é o primeiro de uma série de artigos que serão publicados com o objetivo de mostrar diversas soluções envolvendo o uso do objeto Table Window, o que pode ser considerado por alguns como um dos objetos mais versáteis do Team Developer.

Este primeiro artigo mostrará como carregar os dados de uma tabela do banco de dados na table window, permitirá que os dados sejam modificados e oferecerá funções para salvar no banco de dados as informações que foram alteradas. Basicamente há duas formas de se executar estas atividades e este tutorial mostrará como fazer das duas formas.

Para facilitar o acompanhamento do tutorial será utilizada a tabela COMPANY do banco dedados ISLAND que é o banco padrão que acompanha o Team Developer.

A table window

A Table Window é um objeto visual do Team Developer onde é possível carregar uma matriz de dados em formato de colunas e linhas. Cada coluna é identificada por um título e equivale normalmente a uma coluna de alguma tabela do banco de dados. As linhas representam um registro do banco de dados e normalmente utilizam seu cabeçalho de linha para mostrar indicadores visuais que informam o estado da linha. A forma mais tradicional de trabalhar com a Table WIndow é carregar dados resultado da execução de um comando SELECT. Após o usuário fazer as edições desejadas as linhas editadas são identificadas e o comando SQL apropriado é executado no contexto de cada linha conforme a ação necessária.

Para este tutorial as técnicas serão mostradas baseadas numa janela de edição que foi montada desta forma:

appStartup_TutTWBasic_01

Como é possível observar, a janela possui uma barra de ferramentas com alguns botões para executar as funções básicas a serem tratadas neste tutorial. Os botões executam as tarefas de Carregar dados, Adicionar linha, Salvar edições e um botão para Fechar a janela.

Tudo o que for apresentado aqui funciona para o objeto Child Table Window que é a mesma table window porém, utilizada como objeto child de algum formulário.

Cada coluna da table window deve ser inserida no código utilizando um objeto Table Window Column, conforme a imagem abaixo ilustra:

appStartup_TutTWBasic_02

Cada coluna da table window deve ter seus atributos ajustados para estar em sincronismo com a definição no banco de dados, tipo de dado e tamanho devem ser configurados através do Attribute Inspector para refletir as características de cada coluna, conforme está definido no banco de dados.

Populando a Table Window

A carga dos dados baseia-se na execução de um comando SELECT e seu resultado, o result set, é carregado nas linhas e colunas da table window.

Para fins didáticos o comando SELECT a ser executado para a carga da table window será armazenado numa variável chamada sCmdSelect, conorme ilustrado abaixo:

appStartup_TutTWBasic_03

Este mesmo comando SELECT será utilizado nos dois métodos de carga de dados na table window, por esse motivo foi separado e armazenado numa variável.

Populate automático

O Team Developer disponibiliza uma função para que o desenvolvedor faça a carga dos dados na table window de forma bastante simples, sendo necessário basicamente passar para a função o comando SELECT e informar a forma a ser utilizada para a carga dos dados, detalhes abaixo:

SalTblPopulate

Compila e executa um comando SELECT transferindo as linhas do result set para as linhas da table window.

Sintaxe:

  • Call SalTblPopulate ( hWndTW , hSql , sComando , nMetodo )

Possui os seguintes parâmetros

  • hWndTW – Window Handle – O ponteiro para a table window que será populada. Utilize o nome da table window ou o handle.
  • hSql – Sql Handle – O ponteiro da conexão com o banco de dados que será vinculado à execução e aos resultados obtidos com a execução do comando SELECT. Na maioria dos casos este handle não deve ser utilizado para execução de outros comandos enquanto a table window estiver sendo utilizada.
  • sComando – String -  O comando Select a ser utilizado para popular a table window.
  • nMetodo – Number – Método que indica como a table window deverá ser populada. Possíveis métodos são indicados pelas constantes TBL_FillAll, TBL_FillAllBackground e TBL_FillNormal. Deve ser utilizado apenas uma dessas constantes para cada comando executado.

Caso a função seja executada com sucesso, retornará um booleano TRUE, caso contrário retornará FALSE.

Prosseguindo com a carga da table window deste tutorial, após o comando Select ter sido armazenado na variável sCmdSelect, basta executar a linha abaixo para que a table window seja populada:

Call SalTblPopulate( hWndForm, hSqlMAIN, sCmdSelect, TBL_FillAll )

Esta única linha é o suficiente para fazer a carga do resultado do comando Select. Isso caracteriza este como sendo o método simples de carga de dados numa table window, ou o método automático.

Alguns detalhes devem ser observados.

Quanto a associação das colunas no Select:

  • Na montagem do comando Select, para cada coluna utilizada na cláusula Select uma coluna da table window deve ser usada na clausula Into.
  • Deve-se utilizar o nome completo da coluna da table window, incluindo a referência completa do seu objeto parent.
  • As colunas (ou variáveis ) utilizadas na clausula Into devem ser precedidas pelo caracter : (dois pontos) para indicar que são objetos externos ao banco de dados, oriundos da aplicação.

Obs: a função SalTblPopulate também pode ser usada para popular o objeto Grid Window, controle introduzido no Team Developer 5.2 e estendido nas versões posteriores.

A função SalTblPopulate torna muito prática a carga dos dados em table window pois esconde diversos controles necessários. Ao utilizar o método manual de carga dos dados na table window, sem utilizar SalTblPopulate, deve-se tormar uma série de cuidados.

O trecho de código abaixo ilustra uma possível solução de carga manual, certamente isso pode ser feito de outras formas:

appStartup_TutTWBasic_04

Esta proposta de função para carregar os dados na table window executa diversos controles que SalTblPopulate já faz de forma automática, seguindo a sequencia em que o código foi escrito, pode-se dizer que a função faz o seguinte:

  • A função SalTblReset apaga todos os dados existentes na table window deixando-a no estado inicial para receber dados.
  • A função SqlPrepareAndExecute utiliza o comando sql presente no parâmetro sCmdSelect, compila, executa e retorna o ponteiro para manipulação no parâmetro hSqlMAIN.
  • O comando Loop é utilizado neste ponto para agrupar as instruções de tratamento das repetições envolvendo:
    • preparar a grid para uma nova linha ( inserindo linhas com a função SalTblInsertRow ),
    • setar o contexto de trabalho ( a função SalTblSetContext faz isso ) para a linha recém inserida,
    • recuperar os dados do result set com a função SqlFetchNext
    • e encerrar o laço após todas as linhas terem sido recuperadas.
    • Um detalhe aqui devido a forma como o laço foi montado, após término do fetch no result set a ultima linha da grid precisa ser excluída, a função SalTblDeleteRow faz isso.
  • A função SalTblSetRow move o foco para a primeira linha da table window para que o usuário, após a carga da tabela ter sido concluída possa visualizar as primeiras linhas da table window.
  • A função SalTblSetFlagAnyRows limpa o flag ROW_New que é inserido pelo Team Developer quando executada a função SalTblInsertRow.

 

Salvando alterações nos dados

Uma vez os dados disponíveis na table window o usuário pode modificá-los caso queira. No exemplo, da forma como ele está neste ponto, já é possível que o usuário modifique as informações das células. Nosso próximo passo é salvar no banco de dados estas edições.

Obs: Não faz parte do objetivo deste tutorial mostrar técnicas de como evitar que o usuário modifique a chave primária da tabela, isso será visto em outro momento. Portanto assumiremos que a coluna COMPANY_ID não será modificada e não faremos nenhum controle para garantir isso.

Para salvar edições feitas nesta tabela basicamente é necessário preparar um comando UPDATE, identificar as linhas que foram editadas pelo usuário e executar o comando Update para os dados da linha editada.

Para efeitos didáticos o comando Update será armazenado numa variável chamada sCmdUpdate, conforme definições abaixo:

appStartup_TutTWBasic_05

Baseando-se neste comando é possível partir para a atualização em si. Novamente serão mostrado os métodos automático e manual.

Devido a simplicidade desta operação o código será mostrado com os dois métodos juntos. Como segue abaixo:

appStartup_TutTWBasic_06

Primeiramente deve-se preparar o comando UPDATE que será executado para salvar as linhas editadas. Esta é uma etapa necessária para ambos os métodos e está sendo feita através da chamada da função SqlPrepare, é a primeira instrução deste trecho de código.

Para o método automático basta executar a função SalTblDoUpdates passando como parâmetro o handle da table window onde estão os dados alterados, o handle da conexão com o banco de dados que teve o comando Update preparado e um flag indicando se é para a função remover visualmente da table window o flag de que a linha foi editada.

O método manual é um pouco mais trabalhoso requerendo mais linhas de código, porém é inegável o poder e controle que o método manual oferece numa operação dessas.

O trecho de código executa as seguintes ações:

  • A variável nLinha é usada como ponteiro das linhas a serem trabalhadas. Tem seu valor setado para –1 para que o laço que se segue inicie e percorra todas as linhas da table window.
  • A condição do laço While é o retorno da função SalTblFindNextRow que sempre retornará TRUE caso encontre alguma linha que satisfaça a condição relativa aos flags que a linha possuir, neste caso está filtrando apenas as linhas com flag ROW_Edited = TRUE.  Isso garante que o laço While seja executado apenas para as linhas que efetivamente foram editadas.
  • Após identificar a linha que foi editada é necessário setar o contexto de trabalho para ela, é isso que a função SalTblSetContext faz.
  • Foco setado é preciso executar o comando Update para a linha, isso é feito com a função SqlExecute.
  • O flag de linha editada é removido pela função SalTblSetRowFlags.
  • Quando todas as linhas marcadas com o flag de edição forem atualizadas o laço é encerrado e a função SalTblSetRow move o foco para a primeira linha da table window para que o usuário, após a carga da tabela ter sido concluída possa visualizar as primeiras linhas da table window.

Excluindo linhas da table window

Para a exclusão de linhas os comandos necessários para procurar as linhas marcadas para exclusão e executar a exclusão são similares ao descrito anteriormente para update. As diferenças são:

  • Deve ser compilado um comando DELETE ao invés de updade.
  • O comando para processar automaticamente as exclusões é SalTblDoDeletes
  • Para o método manual a função SalTblFindNextRow deve procurar por linhas marcadas com o flag ROW_MarkDeleted.
  • O flag que deve ser removido com a função SalTblSetRowFlags deve ser ROW_MarkDeleted.

Na prática as alterações são simples e mostradas abaixo, desta vez num único bloco de comandos:

appStartup_TutTWBasic_07

A única função nova neste trecho de código é SalTblDoDeletes que, de forma similar a como foi visto anteriormente, exclui da table window as linhas marcadas para exclusão. Aliás, este é o único ponto que falta para o programa suportar totalmente a exclusão de linhas.

Na table window do Team Developer há uma forma tradicional de marcar linhas para serem excluídas, basta clicar duplamente na área cinza que antecede a linha, área conhecida como row header. Há um evento para capturar o clique e o clique duplo nesta região. O evento chama-se SAM_RowHeaderDoubleClick e é acionado pelo Team Developer sempre que o usuário realiza um clique duplo no header da linhas.

Neste exemplo utilizaremos este evento para marcar a linha para ser excluída. O trecho de código abaixo ilustra isso:

appStartup_TutTWBasic_08

Desta forma, sempre que o usuário clicar duas vezes no header da linha ela será marcada para excusão (ROW_MarkDeleted = TRUE ).

Para remover ROW_MarkDeleted será utilizado o clique simples na linha. Conforme mostrado abaixo:

appStartup_TutTWBasic_09

Desta forma o usuário pode marcar para exclusão quantas linhas quiser, e depois comanda a exclusão em série de todas as linhas marcadas para serem excluídas.

Inserindo linhas na table window

A inclusão de novas linhas na table window pode (visualmente) ser feita de duas formas. Podemos inserir uma linha nova no início ou final da tabela e mover o foco para a linha para que o usuário possa inserir os dados da nova linha.

Outra forma é abrindo um espaço reservado para linhas novas chamado no Team Developer de Split Window. Nesta área reservada as linhas ficam fixas e não desaparecem caso o usuário role as linhas para cima/baixo com as setas de scroll da table window. Para efeitos didáticos faremos de todas estas formas.

Para inserir uma linha nova no topo da table window

Set nRow = SalTblInsertRow( hWndForm, 0 )
Call SalTblSetFocusCell( hWndForm, nRow, tblCOMPANY.colCOMPANY_ID, 0, 0 )

Para inserir uma linha nova no rodapé da table window

Set nRow = SalTblInsertRow( hWndForm, TBL_MaxRow )
Call SalTblSetFocusCell( hWndForm, nRow, tblCOMPANY.colCOMPANY_ID, 0, 0 )

Para criar uma split window e inserir a nova linha dentro da Split Window

Call SalTblDefineSplitWindow( hWndForm, 3, TBL_Split_Adjustable )
Set nRow = SalTblInsertRow( hWndForm, TBL_MinSplitRow )
Call SalTblSetFocusCell( hWndForm, nRow, tblCOMPANY.colCOMPANY_ID, 0, 0 )

Como é possível observar a codificação é muito parecida, portanto está destacado em sublinhado os trechos que diferem.

No exemplo que você poderá fazer download, o programa faz duas perguntas para identificar se deve criar a split window ou se deve inserir a linha nova no topo ou no rodapé da table window.

Vaja abaixo as perguntas e como as janelas se comportarão para cada tipo de resposta:

appStartup_TutTWBasic_11

Caso seja escolhido inserir dados usando a Split Window, a interface se comporta como tal e a split window é criada.

Split Window ativada 

Caso seja respondido “não” a aplicação perguntará se a nova linha deverá ser inserida acima ou abaixo, na table window.

appStartup_TutTWBasic_12

Abaixo seguem uma ilustração mostrando a nova linha inserida no cabeçalho da table window.

appStartup_TutTWBasic_13

No programa exemplo, o código ficou assim:

appStartup_TutTWBasic_14

Após tratar esta questão de onde a linha nova será inserida para que o usuário possa digitar os dados da linha nova, a gravação das linhas novas segue o mesmo padrão adotado para update e delete.

Portanto o código da função que salva as linhas inseridas é esse:

appStartup_TutTWBasic_15

Conclusão

Está pronta uma aplicação CRUD típica em Team Developer feita atrabés de table window mostrando dois métodos de codificação, um mais simples e rápido de codificar (tratado no artigo comom método automático), e outro método mais detalhado que alguns podem achar mais trabalhoso e menos produtivo (chamado no artigo de método manual).

O artigo não trata de questões de produtividade no desenvolvimento, mas sim de forma básica como fazer uma aplicação CRUD. Pretendo mostrar em outros artigos propostas de soluções para obtermos ganho de produtividade bem como explorar muitos outros recursos da table window.

Para fazer o download do código fonte clique aqui.

appStartup_TutTWBasic_00