Manual do Desenvolvedor



Documentos relacionados
SUMÁRIO 1. AULA 6 ENDEREÇAMENTO IP:... 2

Questão Essência do Excel

MANUAL DO ANIMAIL Terti Software

Aula 01 - Formatações prontas e condicionais. Aula 01 - Formatações prontas e condicionais. Sumário. Formatar como Tabela

Orientação a Objetos

Iniciação à Informática

Dicas para usar melhor o Word 2007

Bem- Vindo ao manual de instruções do ECO Editor de COnteúdo.

Manual do Ambiente Moodle para Professores

Fluxo de trabalho do Capture Pro Software: Indexação de código de barras e separação de documentos

Criando Quiz com BrOffice.impress

Lidar com números e estatísticas não é fácil. Reunir esses números numa apresentação pode ser ainda mais complicado.

EXEMPLO DE COMO FAZER UMA MALA DIRETA

Como funciona? SUMÁRIO

Fluxo de trabalho do Capture Pro Software: Indexação de OCR e separação de documentos de código de correção

MANUAL DO GERENCIADOR ESCOLAR WEB

Banco de Dados Microsoft Access: Criar tabelas. Vitor Valerio de Souza Campos

RESTAURAÇÃO NO WINDOWS 8

Barra de ferramentas padrão. Barra de formatação. Barra de desenho Painel de Tarefas

Tutorial de Matlab Francesco Franco

Manual de Atualização Versão

GUIA MUDANÇA E FORMATAÇÃO DE SERVIDOR - MILLENNIUM

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008

Manual de digitação de contas Portal AFPERGS

Banco de Dados Microsoft Access: Criar tabelas

Memória Flash. PdP. Autor: Tiago Lone Nível: Básico Criação: 11/12/2005 Última versão: 18/12/2006. Pesquisa e Desenvolvimento de Produtos

Despachante Express - Software para o despachante documentalista veicular DESPACHANTE EXPRESS MANUAL DO USUÁRIO VERSÃO 1.1

Como incluir artigos:

ROTINAS PADRÕES DO SISTEMAS

Manual SAGe Versão 1.2 (a partir da versão )

EDITORA FERREIRA MP/RJ_EXERCÍCIOS 01

Guia de início rápido do Powersuite

Manual Sistema de Autorização Online GW

Unidade 7: Panes no Excel

GUIA MUDANÇA E FORMATAÇÃO DE SERVIDOR - SLIM

Portal Sindical. Manual Operacional Empresas/Escritórios

Manual Operacional SIGA

Persistência de Dados

Manual Portal Ambipar

Guia Site Empresarial

Microsoft Access: Criar relações para um novo banco de dados. Vitor Valerio de Souza Campos

1. Objetivos do curso 2. 2 Comunicação Interna (CI) 13 3 Ofício 18 4 DEFINIÇÕES GERAIS 23 5 CONCLUSÃO 27

Programação Orientada a Objetos com PHP & MySQL Cookies e Sessões. Prof. MSc. Hugo Souza

Lição 1 - Criação de campos calculados em consultas

Google Drive: Acesse e organize seus arquivos

TUTORIAL DO ACCESS PASSO A PASSO. I. Criar um Novo Banco de Dados. Passos: 1. Abrir o Access 2. Clicar em Criar um novo arquivo

Validando dados de páginas WEB

MANUAL TISS Versão

Manual do Google agenda. criação e compartilhamento de agendas

1.2) Na tela seguinte, o primeiro item a ser selecionado é o Unidade Acumuladora1.

Importação de Dados para o Educacenso 2013

SISTEMAS OPERACIONAIS ABERTOS Prof. Ricardo Rodrigues Barcelar

Funções básicas Cronograma Cronograma Funções Básicas

PORTAL DE COMPRAS SÃO JOSÉ DO RIO PRETO

&XUVRGH,QWURGXomRDR (GLWRUGH3ODQLOKDV([FHO

INTRODUÇÃO AO WINDOWS

Tutorial para envio de comunicados e SMS

Procedimentos para Reinstalação do Sisloc

Associação Educacional Dom Bosco Curso de Engenharia 1º ano

O Excel é um programa de computador desenvolvido para gerenciar dados na forma de planilhas.

FERRAMENTAS DE COLABORAÇÃO CORPORATIVA

- Versão 1.0 Página 1

Gerencie a sala de espera e garanta a satisfação dos pacientes

Atualizaça o do Maker

Arquitetura de Rede de Computadores

Manual AGENDA DE BACKUP

3. No painel da direita, dê um clique com o botão direito do mouse em qualquer espaço livre (área em branco).

Novell. Novell Teaming 1.0. novdocx (pt-br) 6 April 2007 EXPLORAR O PORTLET BEM-VINDO DESCUBRA SEU CAMINHO USANDO O NOVELL TEAMING NAVIGATOR

Lazarus pelo SVN Linux/Windows

Microsoft Office 2007

Parte 5 LibreOffice Base

Armazenamento de Dados. Prof. Antonio Almeida de Barros Junior

Curso: Redes II (Heterogênea e Convergente) Tema da Aula: Características Roteamento

ArpPrintServer. Sistema de Gerenciamento de Impressão By Netsource Rev: 02

Resolvendo problemas de conexão de rede wireless no pregão 83/2008

Status. Barra de Título. Barra de Menu. Barra de. Ferramentas Padrão. Caixa de nomes. Barra de. Ferramentas de Formatação. Indicadores de Coluna

Engenharia de Software III

WF Processos. Manual de Instruções

Planilha Eletrônica Excel

ÍNDICE... 2 INTRODUÇÃO... 4

Prática 6 ActionScript

Professor: Macêdo Firmino Disciplina: Sistemas Operacionais de Rede

PROGRAMAÇÃO ESTRUTURADA. CC 2º Período

Sumário: Fluxo Operacional... 3 Contatos Agenda Online Reservas de Salas Tarefas... 42

LIÇÃO 1 - USANDO O GRAVADOR DE MACROS

Usuário deve preencher o código do Registro da sua Empresa (composto de 4 dígitos), sua senha, e teclar o botão ENVIAR.

Apostilas OBJETIVA Escrevente Técnico Judiciário TJ Tribunal de Justiça do Estado de São Paulo - Concurso Público Caderno 1.

QUALIDATA Soluções em Informática. Módulo CIEE com convênio empresas

TUTORIAL PRÁTICO SOBRE Git. Versão 1.1

MANUAL EXPORTAÇÃO IMPORTAÇÃO

Usando o do-file editor Automatizando o Stata

Microsoft Office PowerPoint 2007

AULA 06 CRIAÇÃO DE USUÁRIOS

MANUAL DE UTILIZAÇÃO Aplicativo Controle de Estoque Desktop

ANDRÉ APARECIDO DA SILVA APOSTILA BÁSICA SOBRE O POWERPOINT 2007

Inventario de produtos

MANUAL DE UTILIZAÇÃO SISTEMA DE CADASTRO INTRANET

Transcrição:

Manual do Desenvolvedor Fascículo I Junho/2011 Gerenciando a Abertura de Views, ModalPanels e DataFile s Para Melhor Desempenho Esse documento é uma obra intelectual de uso restrito da Atual Sistemas. Qualquer ato de leitura, alteração, cópia ou distribuição, completa ou parcial deve ser feita somente sob autorização expressa. A posse ou uso não autorizado desse documento, ou do seu conteúdo completo ou parcial, constitui-se um uma violação direta dos direitos de intelectualidade e será julgada conforme o rigor da lei.

ii Fascículos do Desenvolvedor Conteúdos Trabalhando Com Janelas Visuais Deferred 1 Abrindo Tabelas No Momento Certo 9 Usando Comando Open As, Slots e Apoio dos Recursos Globais 12 Recomendações Para um Bom Fonte 15 Ativação e Desativação de Janelas O Método Sugerido 20

Capítulo 1 Trabalhando Com Janelas Visuais Deferred Ao desenvolver aplicações gráficas, para que haja uma melhor interação entre Usuário-Software, se faz um extensivo uso de Janelas. Janelas diferem entre si não somente em aparência e conteúdo, mas principalmente em comportamento. Por isso, muitas vezes um sistema requer um grande número de janelas. Em cada uma dessas janelas, há componentes e objetos que compõe o seu conteúdo e as tornam necessárias. Quando temos que lidar com um grande número de janelas, cada uma com os seus componentes, isso pode significar a necessidade de um grande volume de recursos do sistema, o que requer um bom gerenciamento. Esse capítulo aborda que recursos o Visual DataFlex nos dispões, bem como que recursos foram desenvolvidos pela própria Atual Sistemas, para que não venhamos a estar desperdiçando recursos necessários ao inserir novas janelas no sistema. Como o Visual DataFlex Classifica Janelas Seguindo o modelo utilizado no Visual DataFlex, nós podemos classificar janelas em duas categorias (há mais tipos de janelas): Modal Janelas modal são caracterizadas por não permitirem que o usuário selecione janelas que já foram abertas anteriores a ela na mesma aplicação. Em Visual DataFlex nós usamos as classes ModalPanel e ReportPanel para criar janelas modal, sendo a ultima classe usada apenas para relatórios. Modeless Janelas modeless são usadas em casos quando não desejamos impedir que usuário faça outras tarefas na aplicação enquanto essa janela está aberta. Em Visual DataFlex nós usamos as classes View e ReportView para criar janelas modaless, sendo a ultima classe usada apenas para relatórios. Dica Consulte o apêndice sob título Ativação e Desativação de Janelas O Método Sugerido. Ativação Atrasada de Janelas Todos os objetos visuais que pertencem ao escopo (que estão dentro) do objeto Client_Area devem ser criados no regime Deferred (efeito de criação atrasada). Isso significa que o conteúdo dessas janelas só será criado quando elas forem ativadas pela primeira vez. Isso evita o consumo desnecessário de memória e reduz o tempo necessário para iniciar a aplicação Para tornar uma View ou ReportView deferred, troque o valor da propriedade Deferred Object para True, ou faça a substituição do código A pelo código B seguindo as características do seu objeto. //Código A Activate_View Activate_MeuRelatorio for MeuRelatorio Object MeuRelatorio is a ReportView // Restante do código _Object Troque o código acima para //Código B Deferred_View Activate_MeuRelatorio for ; Object MeuRelaorio is a ReportView // Restante do código Cd Object

2 Fascículos do Desenvolvedor Para objetos ModalPanel ou ReportPanel, apenas troque a propriedade CD Popup para true. Uma vez que você determina que um objeto visual tenha a inicialização atrasada, nenhum de seus objetos filhos será criado até que você chame o método de disparo, no caso Activate para View s e ReportView s (Modeless) e Popup_Modal para ModalPanel s e ReportPanel s (Modal). Isso significa que até que algumas dessas funções sejam chamadas, nenhuma informação referente ao objeto e aos seus filhos poderá ser manipulada. Para desativar objetos visuais Deferred, se você estiver lidando com um objeto modeless, use o procedimento Deactivate. Para diálogos modais envie Close_Panel para o componente segundo o nome dele. Atenção: Ao passar um componente para deferred, não referencie objetos filhos de componentes modeless (ex: ReportPanel, ModalPanel...) usando o nome do componente no endereço. Por exemplo, caso você tenha um componente modeless chamado Consulta_SL que possui um objeto filho chamado Exata, não referencie esse objeto com a seguinte síntese: Send AlgumaCoisa to (Exata(Consulta_SL(Self))) Nesses casos, não use o nome do componente visual. Ao invés disso, use apenas o self. Caso você tenha que usar realmente o nome do componente, acrescente _CD no final do nome do componente. Isso é porque um objeto Consulta_SL_CD será criado em tempo de execução de modo transparente e é esse objeto quem abriga os controles filhos. // Exemplo SEM o nome do componente Send AlgumaCoisa to (Exata(Self)) // Exemplo COM o nome do componente Set Label of (Consulta_SL_CD(Self)) to "Consulta Geral" Send Close_Panel to (Consulta_SL_CD(Self)) Como Enviar Dados Necessários Após a Ativação da Janela Já que os dados de um objeto só ficam disponíveis após a sua criação, foram desenvolvidos e disponibilizados sistemas para compartilhamento de dados que se comportem de maneira segura e adequada entre os módulos visuais. Esses são o Sistema de Parâmetros Globais, Sistema de Registros Globais e o Gerenciador de Dados Múltiplos. Seguindo a ordem em que foram alistados tente dar prioridade a eles. Caso o primeiro não seja suficiente, tente o segundo, se esse também não for suficiente tente o terceiro. Portanto segue abaixo como resolver algumas das situações, o que requererá criatividade do programador na escolha apropriada. SPG Quando é necessário passar um parâmetro Talvez uma informação que era definida antes da ativação de módulo possa ser transformada em um parâmetro no sistema de recursos globais. Por exemplo: O ForBax tinha de abrir o ForExc em dois modos que diferiam no botão que o usuário clicava para abrir o ForExc. Um dos botões era para consulta e, portanto tudo que estivesse relacionado com alterações teria que ser desabilitado a fim de que toda a tela se comportasse em modo somente leitura. O outro deveria permitir que o usuário fizesse alterações. Essa informação deveria estar disponível para o diálogo durante a sua criação. Como resolver a situação? Foi inserido um parâmetro no Sistema de Parâmetros Globais. Ao ser aberto, o ForExc procura pelo parâmetro. Caso ele seja encontrado, se entende que a exibição deve ser em modo somente leitura. Durante a consulta se realiza a exclusão do parâmetro já que ele será consultado apenas uma vez durante a ativação do objeto visual. O código abaixo demonstra a criação do parâmetro antes da ativação do diálogo. // ForBax.vw cabeçalho Use vdfclasses.pkg Use ForExc.vw // Dentro do ForBax...

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 3 // Procedure OnClick If (FORMOV.RECIBO > 0) Begin Integer iresult Get InserirParametro of (orecursosglobais(self)) FOREXC_SOMENTE_LEITURA to iresult Send Activate_ForExc Send Deactivate_Group to (ForBax(Self)) _Procedure Note que a constante que FOREXC_SOMENTE_LEITURA não está definida no arquivo FORBAX.VW, mas no FOREXC.VW já que é lá que está o fonte a quem o parâmetro se refere. // ForExc.vw Cabeçalho. Use vdfclasses.pkg Define FOREXC_SOMENTE_LEITURA for CS"FOREXC_SOMENTE_LEITURA" // Dentro do ForExc... // Procedure Activate If ((DeletarParametro(oRecursosGlobais(Self), FOREXC_SOMENTE_LEITURA)) = OK_) Begin Set Label of (ForExc(Self)) to "Consulta de Recibo - Fornecedor" Set Bitmap of (BtnExcluir(Self)) to "" Set Bitmap of (BtnLimpar(Self)) to "" Set Enabled_State of (BtnExcluir(Self)) to False Set Enabled_State of (BtnLimpar(Self)) to False Else Begin Set Label of (ForExc(Self)) to "Exclusão de Recibo - Fornecedor" Send SetaJPG "Excluir.jpg" (BtnExcluir(Self)) Send SetaJPG "Limpar.jpg" (BtnLimpar(Self)) Set Enabled_State of (BtnExcluir(Self)) to True Set Enabled_State of (BtnLimpar(Self)) to True Forward Send Activate _Procedure Conforme você pode notar, você deverá usar essas funções a partir do objeto orecursosglobais. Esse objeto deve ser sempre usado com a finalidade do compartilhamento de dados globais entre views. Quanto a função DeletarParametro ela funciona de maneira idêntica a função ConsultarParametro, com a única diferença que ela apaga o parâmetro quando o encontra. Caso o parâmetro seja encontrado o retorno de ambas as funções será um OK_, caso contrário será um INVALID_HANDLE_VALUE. Um parâmetro é uma string. Como você deve ter notado, foi criada uma constante que em tempo de compilação deixa de existir e é substituída a referência da constante pelo seu valor. Sempre recorra ao uso de constantes para evitar erros de programação difíceis de detectar. Use sempre como prefixo o nome do objeto que precisa do parâmetro (no exemplo acima FORBAX) usando um underscore (_) onde ficaria o espaço e em seguida descrevendo a finalidade do parâmetro separada por underscore onde houver necessidade de espaço. Tudo em maiúsculo. Nomeie a constante que armazenar o valor de modo idêntico ao valor e lembre-se que você não pode ter dois parâmetros iguais no SPG. Então a string deve ser única. Você pode descobrir se houve uma tentativa de criar um parâmetro que já existe por verificar se o retorno de InserirParametro é INVALID_HANDLE_VALUE. Lembre. O valor string de um parâmetro deve atender as seguintes expectativas: Estar armazenado em uma constante de compilação e ser referido por essa constante sempre. A string deve ser maiúscula e deve-se usar underscore (_) no lugar de espaço. Deve-se colocar o nome do módulo que tornou o parâmetro necessário seguido por underscore. A constante deve ser nomeada segundo o seu valor. O valor deve ser único em todo o sistema. Nota: Explicações mais detalhadas e específicas podem ser encontradas nos comentários do arquivo classes.pkg. 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

4 Fascículos do Desenvolvedor SRG Quando é Necessário Passar um Registro Agora que você está um pouco familiarizado com o sistema de troca de dados entre objetos visuais, imagine que você tenha que passar uma informação que não tem um valor fixo determinado. Por exemplo, o diálogo Acrescimo (Acrescimo.dg) não pode ser Deferred porque um de seu controles recebe um valor antes de ser exibido. E o valor de um dos controles é recuperado como resultado após ser fechado. Para resolver esse problema, basta se recorrer ao Sistema de Registros Globais. Um registro é constituído de identificador e um valor. Um identificador, ou chave, deve seguir as seguintes regras: Estar armazenado em uma constante de compilação e ser referido por essa constante sempre. A string deve ser maiúscula e deve usar underscore (_) no lugar de espaço. Deve-se colocar o nome do módulo que tornou o parâmetro necessário seguido por underscore (FORBAX_). A constante deve ser nomeada segundo o seu valor, porém usando um prefixo REG_ (Ex. REG_FORBAX_MEU_REGISTRO). O identificador deve ser único em todo o sistema. O valor do registro pode ser de qualquer tipo, sem exceções. No caso do problema acima, segue abaixo o modelo de como se resolveria a questão da atribuição e retorno do valor usando-se um registro. // ESTMOV.VW cabeçalho Use vdfclasses.pkg Use Acrecimo.dg // Dentro do EstMov... // Procedure OnClick Integer iresult Number nvracrecimo If (ESTMOV.PRE_VENDA = 'S' and CADOPE.VENDA = 'S' and ESTMOV.VR_BRUTO > 0 and ; ESTMOV.DATA_EXC = 0) Begin Get CriarRegistro of (orecursosglobais(self)) REG_ESTMOV_ACRESCIMO ESTMOV.VRBRUTO To iresult Send Popup_Modal to (Acrescimo(Self)) Get LerRegistro of (orecursosglobais(self)) REG_ESTMOV_ACRESCIMO (&nvracrescimo) To iresult Get RemoverRegistro of (orecursosglobais(self)) REG_ESTMOV_ACRESCIMO to iresult If (nvracrecimo > 0) Begin // Faz aqui todos os demais processos. _Procedure A seguir note o que será necessário fazer no arquivo Acrecimo.dg. // ACRESCIMO.DG cabeçalho Use vdfclasses.pkg Define REG_ESTMOV_ACRESCIMO for CS"ESTMOV_ACRESCIMO" // Dentro de Acrescimo... // Procedure Activating Returns Integer Integer iresult Number nvracrecimo Get LerRegistro of (orecursosglobais(self)) REG_ESTMOV_ACRESCIMO (&nvracrescimo) To iresult If (iresult = OK_) Set Value of (obruto(dados(self))) to nvracrecimo Forward Send Msg_Activating to iresult Procedure_Return iresult _Procedure Procedure Deactivating Returns Integer Integer iresult Number nvracrecimo

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 5 Get Value of (ovalor(dados(self))) to nvracrecimo Get AlterarRegistro of (orecursosglobais(self)) REG_ESTMOV_ACRESCIMO nvracrescimo To iresult Forward Send Msg_Deactivating to iresult Procedure_Return iresult _Procedure Os exemplos acima mostram como usar o sistema de registros. É claro que como você o usará não se limitará somente a um modelo como esse. Para o uso de registro você lidará com as funções CriarRegistro, AlterarRegistro, LerRegistro e RemoverRegistro. Todas essas funções quando funcionam com êxito retornam OK_ e quando falham retornam INVALID_HANDLE_VALUE. Sempre verifique esse valor de retorno, pois caso qualquer uma das funções falhem, nenhum efeito ocorrerá no sistema de registros. Por exemplo, suponhamos que por descuido você crie uma chave e não a remova em determinada situação. Ao tentar criá-la novamente, se identificará que uma chave já existe e a função CriarRegistro irá falhar. O que significa que o valor que você passou não será armazenado porque uma chave idêntica foi encontrada. Caso você não verifique o valor de CriarRegistro, nenhum problema aparente será notado. Quando você tentar lê a chave, você irá encontrá-la com o mesmo valor que ela estava antes da tentativa frustrada de criar uma nova chave. O que poderá trazer resultados inesperados para a sua lógica. Nota: Explicações mais detalhadas e específicas podem ser encontradas nos comentários do arquivo classes.pkg. GDM Quando é Necessário Passar Dados Múltiplos Em alguns casos talvez o fonte fique extremamente complexo e trabalhoso se você tiver que lidar com registros. Isso se dá principalmente em casos onde diversos valores devem ser informados em conjunto. Nesse caso talvez seja melhor usar um contêiner. Para entender em que situações deve se usar um contêiner tenha sempre em mente os seguintes passos. Se os pontos delineados abaixo forem atendidos, então você deve usar um contêiner para a sua tarefa. Não é possível ou não é benéfico transmitir a informação com um ou mais parâmetros. Não é possível ou não é benéfico transmitir a informação com um ou mais registros. O uso de contêiner tornará o fonte mais fácil de entender. A quantidade de dados em questão varia conforme as circunstâncias e geralmente é desconhecido (por ex. Às vezes eu tenho A e B e as vezes eu tenho A, B, C e D). Precisa ser listado em uma ordem linear. Caso pelo menos quatro pontos sejam verdadeiros no seu caso, então talvez seja apropriado usar um contêiner. A definição de contêiner e o uso são bem simples. Um contêiner é um Array com um identificador único, similar ao utilizado pelo sistema de registros globais. O identificador deve ser passado para se usar o contêiner. Esse identificador é uma string e a seguinte convenção deve ser usada para se nomear um identificador. Estar armazenado em uma constante de compilação e ser referido sempre por essa constante. A string deve ser em maiúsculo e deve usar underscore (_) no lugar do espaço. Deve-se colocar o nome do módulo que tornou o parâmetro necessário seguido por underscore (FORBAX_). A constante deve ser nomeada segundo o seu valor, porém usando um prefixo CON_ (Ex. CON_FORBAX_MEU_REGISTRO). O identificador deve ser único em todo o sistema. Por exemplo, o procedimento mgravalogoperacao que é responsável por exibir o diálogo LogOperacao costumava fornecer dados para a grid que havia no diálogo. Esses dados eram fornecidos diretamente se usando um handle para ter acesso a grid. Assim eram acrescidas informações ao conteúdo da grid e verificada a quantidade que fora inserida. O exemplo parcial abaixo demonstra isso. // PREVENT.PKG 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

6 Fascículos do Desenvolvedor Procedure mgravalogoperacao String stabela String sacao Move (Eval(oGridOperacoes(LogOperacao(Self)))) to hgrid Send Delete_Data to hgrid move 0 to icount Move (Trim(Lowercase(sFile))) to sfile If_ (Left(sFile,3) = 'log' and right(sfile,4) = '.log') Begin move '' to dvar Direct_Input channel 1 sfile Repeat Readln channel 1 svar move (Seqeof) to bacaboulinhas If_ (Trim(sVar) <> '') begin Send Add_Item to hgrid msg_none (left(svar,39)) Send Add_Item to hgrid msg_none (mid(svar,200,45)) Set Item_Shadow_State of hgrid item icount to True Set Item_Shadow_State of hgrid item (icount+1) to True Add 2 to icount end Until (bacaboulinhas) Close_Input channel 1 sfile If_ (Item_Count(hGrid) > 0) Begin Set Label of (txtformulario(omensagem(logoperacao(self)))) to sformulario Set Visible_State of (txtabortar(logoperacao(self))) to (Right(sAcao,1) = 'X') Send Popup to (LogOperacao(Self)) _Procedure Esse modelo funciona com componentes que não são iniciados atrasados (em modo deferred). Uma vez que o LogOperacao passou a ter a inicialização atrasado, se tornou necessário um método para o transporte dessas informações que eram reunidas antes da abertura do diálogo. Como você pode notar também, além ser necessário preencher a grid, também era necessário informar o valor do Label de um TextBox e o Visible_State de outro. Porém esse dois problemas podem ser facilmente resolvidos com um registro e um parâmetro para cada um respectivamente. No caso da grid apenas um contêiner de dados resolveria o problema, e isso é ilustrado na solução abaixo. // PREVENT.PKG Procedure mgravalogoperacao String stabela String sacao Get CriarConteiner of (orecursosglobais(self)) CON_LOGOPERACAO_GRADE to iresult Send Delete_Data to (Conteiner(oRecursosGlobais(Self), CON_LOGOPERACAO_GRADE)) move 0 to icount

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 7 Move (Trim(Lowercase(sFile))) to sfile If_ (Left(sFile,3) = 'log' and right(sfile,4) = '.log') Begin move '' to dvar Direct_Input channel 1 sfile Repeat Readln channel 1 svar move (Seqeof) to bacaboulinhas If_ (Trim(sVar) <> '') begin Set ValorConteiner of (orecursosglobais(self)) CON_LOGOPERACAO_GRADE item ; (Item_Count(Conteiner(oRecursosGlobais(Self), CON_LOGOPERACAO_GRADE))) to ; (Left(sVar,39)) Set ValorConteiner of (orecursosglobais(self)) CON_LOGOPERACAO_GRADE item ; (Item_Count(Conteiner(oRecursosGlobais(Self), CON_LOGOPERACAO_GRADE))) ; to (Mid(sVar,200,45)) end Until (bacaboulinhas) Close_Input channel 1 sfile If_ ((Item_Count(Conteiner(oRecursosGlobais(Self), CON_LOGOPERACAO_GRADE))) > 0) Begin Get CriarRegistro of (orecursosglobais(self)) REG_LOGOPERACAO_FORMULARIO sformulario ; to iresult If (Right(sAcao,1) = 'X') Get InserirParametro of (orecursosglobais(self)) ; LOGOPERACAO_ABORTAR_VISIVEL to iresult Send Popup to (LogOperacao(Self)) Get RemoverConteiner of (orecursosglobais(self)) CON_LOGOPERACAO_GRADE to iresult _Procedure A função CriarConteiner cria um contêiner com o identificador único que foi passado para ela. Caso nenhum contêiner com o mesmo identificador tenha sido criado e tudo corra bem, é retornado OK_; caso contrário retorna INVALID_HANDLE_VALUE. Um contêiner é simplesmente um objeto csettabela, uma classe derivada da classe Set (um implemento de Array). A função Conteiner retorna um handle para que você tenha acesso a esse objeto. Porém, evite o uso dessa função e sempre copie o valor retornado a partir dela para um handle, caso você tenha que recorrer a função Conteiner constantemente. Isso porque toda vez que a função Contener é chamada, uma busca é realizada para achar o contêiner segundo o identificador informado. Caso nenhum contêiner seja encontrado, INVALID_HANDLE_VALUE é retornado. O método propriedade ValorConteiner é usado para se alterar/consultar os elementos do contêiner informado (usando Get/Set respectivamente). Caso deseje alterar os elementos do contêiner por um handle, terá o mesmo efeito que o uso desse método. Por fim, o método RemoverConteiner é usado para remover o contêiner do Gerenciador de Dados Múltiplos. Lembre-se sempre de usar esse método e deixe que o gerenciador se encarregue de destruir o contêiner com seus elementos. Nunca envie Destroy para o handle de algum contêiner, porque a referência permanecerá no gerenciador. Segue abaixo as alterações que seriam necessárias no Diálogo para que o fonte acima desse certo. // LOGOPERACAO.DG Define CON_LOGOPERACAO_GRADE for CS"LOGOPERACAO_GRADE" Define REG_LOGOPERACAO_FORMULARIO for CS"LOGOPERACAO_GRADE" 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

8 Fascículos do Desenvolvedor Define LOGOPERACAO_ABORTAR_VISIVEL for CS"LOGOPERECAO_ABORTAR_VISIVEL" Cd_Popup_Object LogOperacao is a ModalPanel Faz declaração de objetos. Procedure Activating Returns Integer Integer iresult iindice ilimite Handle hconteiner String sformulario Set Dynamic_Update_State of (ogridoperacoes(self)) to False Get Conteiner of (orecursosglobais(self)) CON_LOGOPERACAO_GRADE to hconteiner If (hconteiner <> INVALID_HANDLE_VALUE) Begin Move ((Item_Count(hConteiner)) - 1) to ilimite For iindice from 0 to ilimite Send Add_Item to (ogridoperacoes(self)) msg_none ; (ValorConteiner(oRecursosGlobais(Self), CON_LOGOPERACAO_GRADE, iindice)) Set Item_Shadow_State of (ogridoperacoes(self)) ; item ((Item_Count(oGridOperacoes(Self))) -1) to True Loop Set Dynamic_Update_State of (ogridoperacoes(self)) to True Get DeletarParametro of (orecursosglobais(self)) LOGOPERACAO_ABORTAR_VISIVEL to iresult Set Visible_State of (txtabortar(self)) to (iresult = OK_) Get LerRegistro of (orecursosglobais(self)) ; REG_LOGOPERACAO_FORMULARIO (&sformulario) to iresult If (iresult = OK_) Set Label of (txtformulario(omensagem(self))) to sformulario Forward Get Msg_Activating to iresult Procedure_Return iresult _Procedure Procedure Deactivating Returns Integer Integer iresult Get RemoverRegistro of (orecursosglobais(self)) REG_LOGOPERACAO_FORMULARIO to iresult Forward Get Msg_Deactivating to iresult Procedure_Return iresult _Procedure Cd Object Conforme demonstrado nessa situação ilustrativa, cslottabeladinamica se encarrega de todos os processos envolvidos, eliminando a necessidade de você ter de se preocupar com o slot em si e com outros dados como a numeração dos campos da tabela. O procedimento CriarTabelaDinamica é responsável por reservar o slot e reunir os meta-dados referente ao nome das colunas. A propriedade phtabela contém o manipulador do slot reservado. A função Campo retorna o número do campo conforme a string passada. Por fim, a função CampoValorCorrente retorna o valor do campo informado. Após ser utilizado, o objeto deve ser destruído o quanto antes. Durante a destruição, a classe se encarrega de liberar o slot e fechar a tabela. Nota A classe crecursosglobais possui uma série de usos não alistados aqui. Explicações mais detalhadas e específicas podem ser encontradas nos comentários do arquivo classes.pkg.

Capítulo 2 Abrindo Tabelas No Momento Certo Um bom desenvolvedor zela pelo bom uso de recursos de sistemas, e quando se fala de recursos e otimizar, a base de dados sempre terá o seu lugar nessa preocupação. Principalmente em nosso caso, o bom gerenciamento de recursos da base é extremamente necessário já que a base de dados embutida do Visual DataFlex é uma base não relacional. Assim, cada tabela possui um arquivo dedicado que é acessado usando recursos comuns do computador, da rede local ou do domínio. Esse capítulo aborda como fazer o bom uso de comandos para abertura de tabelas de maneira que não desperdicemos recursos reservando tabelas que no final não usaremos. Bom uso do comando Open Antes que uma tabela (ou arquivo de dados) possa ser referenciada no código, junto com os respectivos campos, para que então seus dados sejam lidos ou alterados, é necessário abrir essa tabela. Para isso, o Visual DataFlex usa o Comando Open. Esse comando diz para o compilador que ele conhece essa tabela e seus campos, e durante a execução do programa ele reserva a tabela para uso. O comando open deve ser usado com critério e as tabelas não devem ser abertas até que elas tenham realmente de ser utilizadas. Por isso, devem ser removidos os comandos open que estão no escopo global dos arquivos. Atualmente muitos cabeçalhos estão em uma situação semelhante a do nosso exemplo abaixo. // ACAXPRE.RV Use vdfclasses.pkg Open CAXPRE Open FCAXPRE Deferred_View Activate_ACaxPre For ; Object ACaxPre is a ReportView // Fonte continua... Cd Object Isso faz com que, nesse exemplo, os arquivos CAXPRE e FCAXPRE sejam abertos durante a criação do objeto Client_Area. O que derruba a desempenho do sistema desde a inicialização quando não há necessidade de que esses arquivos estejam abertos. Na verdade eles deveriam estar dentro de um objeto deferred, como no exemplo abaixo. // ACAXPRE.RV Use vdfclasses.pkg Deferred_View Activate_ACaxPre For ; Object ACaxPre is a ReportView Open CAXPRE Open FCAXPRE // Fonte continua... Cd Object Sempre deixe comandos de open dentro de algum escopo fechado. No caso de objetos, o escopo só será fechado se o objeto for deferred.

10 Fascículos do Desenvolvedor Sempre que possível, use Declare_DataFile Em algumas situações, não é possível compilar a aplicação porque fora feita referência a alguma tabela que ainda não fora aberta. Para solucionar esse problema, o programador geralmente recorre ao comando Open. Embora essa tenha sido a solução para o problema em versões antigas do VDF, as versões mais recentes do Visual DataFlex dispões de outro recurso para resolver esse problema fazendo bom uso dos recursos do sistema ao mesmo tempo. O Comando Declare_DataFile tem o mesmo efeito em tempo de compilação que o comando Open, com a única diferença que ele não reservará a tabela para uso em tempo de execução. Isso se torna extremamente útil em aplicações que fazem extenso uso de DDO s, já que os dicionários de dados se responsabilizarão em abrir a tabela no momento certo. Assim, em pacotes (.PKG) que precisamos usar tabelas do banco para prover funcionalidades para Janelas que possuem DDO s, mas não se é possível compilar esses pacotes por falta do comando Open, basta usar o comando Declare_DataFile neste pacotes. Veja um exemplo caso no código abaixo. // FUNCOES.PKG Open CADPRO Open ESTSAL Function fvalida_desconto Global Date ddata Returns Number If (CADPRO.DESCONTO_OK = "S") Begin // Fonte continua... _Function Nesse exemplo, o comando Open precisa estar presente no fonte para que seja possível compilar a linha que faz referência ao CADPRO.DESCONTO_OK. Porém o fato de o comando Open estar no escopo global desse PKG faz com que esse comando open seja executado durante a inicialização em algum ponto onde esse arquivo é incluso no projeto. Se nós estamos usando o Open apenas para garantir a compilação, o comando Declare_DataFile seria suficiente nesse caso. Veja o exemplo abaixo. // FUNCOES.PKG Declare_Datafile CADPRO Declare_Datafile ESTSAL Function fvalida_desconto Global Date ddata Returns Number If (CADPRO.DESCONTO_OK = "S") Begin // Fonte continua... _Function Nesse exemplo, a tabela não será aberta quando o PKG for incluso no projeto durante a inicialização do programa e nós conseguiremos compilar esse arquivo sem nenhum problema com a referência ao campo CADPRO.DESCONTO_OK. Contudo, nesse caso, quando fvalida_desconto fosse chamada, alguma outra parte da aplicação deveria se responsabilizar em já ter essas tabelas abertas. Se não é possível garantir que a função fvalida_desconto será chamada apenas com CADPRO e ESTSAL abertos, então é mais seguro usar o comando Open mesmo, mas nesse caso deve se usar da seguinte forma. // FUNCOES.PKG Function fvalida_desconto Global Date ddata Returns Number Open CADPRO Open ESTSAL If (CADPRO.DESCONTO_OK = "S") Begin // Fonte continua... _Function Nesse ultimo caso, o open abrirá a tabela e, por ele não estar no escopo global, isso só ocorrerá quando a função fvalida_desconto for chamada. Essa deve ser a ultima alternativa para abrir a tabela. Geralmente, funções que acessam dados de tabelas são chamadas a partir de Janelas que já abriram essas tabelas, o que torna o uso de Declare_DataFile mais desejável para um fonte mais compreensível e seguro. Isso, porque se você usar o Open dentro da função, você terá de usálo em cada função que precise fazer uso do arquivo em questão (no nosso exemplo, o ESTSAL). Resumindo: Use o comando Open somente quando Declare_DataFile não puder realmente resolver a situação.

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 11 Os arquivos DD s já estão fazendo uso desse tipo de recurso, por declararem em tempo de compilação que usam uma tabela (ou arquivo de dados), mas só tentam abrir tais tabelas no momento em que uma instancia da classe DD é criada. Veja o exemplo. // ccadmsadatadictionary.dd Use DataDict.pkg Declare_Datafile CADSEC Declare_Datafile CADMSA Declare_Datafile CADFUN Class ccadmsadatadictionary is a DataDictionary Procedure Construct_Object Open CADSEC Open CADMSA Open CADFUN Forward Send Construct_Object // Fonte continua... _Procedure // Fonte continua... _Class Uma classe de Dicionário de Dados como a do exemplo dado acima só abrirá o arquivo no momento em que a primeira instancia dela for criada, o que pode significar que esse arquivo nunca será aberto se a janela que faz uso dele não for usada pelo usuário durante a execução. Dessa forma, nenhum recurso do sistema é usado a menos que seja de fato necessário. 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

Capítulo 3 Usando Comando Open As, Slots e Apoio dos Recursos Globais A base de dados do Visual DataFlex utiliza um método para organizar suas tabelas, ou arquivos de dados, de modo que cada uma delas receba um número em uma lista que é chamado de FileList. Assim cada tabela no sistema possui um número, e cada número desse é tecnicamente chamado de slot. Esse capítulo abordará algumas técnicas providas pelo Visual DataFlex e por bibliotecas desenvolvidas pela Atual Sistemas para fazermos bom uso desses slots para determinados tipos de consultas. Abrindo Uma Cópia de Um Arquivo de Dados Em alguns casos nós precisamos realizar uma consulta em uma tabela, mas isso não é possível porque nós temos dados no buffer daquela tabela que não podem ser afetados. Ou então, pode acontecer de precisamos de comparar dois registros da mesma tabela. Como podemos alcançar um registro específico de uma tabela sem afetar o registro corrente do buffer? O comando Open As serve justamente para esse propósito. Com esse comando, nós podemos abrir uma cópia de uma tabela em um slot vazio no banco de dados e realizar consultas nesse novo slot sem afetar o buffer da tabela original. Todas as operações comuns de consulta podem ser realizadas usando-se comandos de acesso a dados de um arquivo de dados que usam números como referências ao invés do nome simbólico dos campos (ex. Set_Field_Value, Get_Field_Value, VFind). Ao final da tarefa, depois de termos realizado a consulta, nós nunca deixamos de chamar o comando Close para liberar a cópia. Embora essa técnica não seja nova há alguns reajuste cuja implementação é necessária. Isso porque é preciso uma segurança maior na hora de decidir qual slot vazio deve ser utilizado. Caso seja aberta uma tabela sobre um slot que está sendo usado temporariamente por outra cópia, isso resultará em problemas que inicialmente podem passar despercebidos, mas que são completamente comprometedores. Atenção: Não use reread ou operações de DDO que fazem alterações em arquivos de dados quando houver alguma cópia de um arquivo de dados aberta. Por exemplo, era comum o uso da função fnewfile ou um número específico (geralmente 1500) para determinar o slot que a cópia do arquivo seria aberta. Esses métodos não são seguros e devem ser corrigidos. Segue abaixo uma situação típica. // CADIMP.RV Conteúdo Integer icampoid icampocaminho icampodescricao icampoestacao Integer iid iidfile ifile String scaminho sdescricao scaminhofile sdescricaofile sestacao Get Value of (ID(Self)) to iid Get Value of (Caminho(Self)) to scaminho Get Value of (Descricao(Self)) to sdescricao Get_FieldNumber CADIMP.ID to icampoid Get_FieldNumber CADIMP.CAMINHO to icampocaminho Get_FieldNumber CADIMP.DESCRICAO to icampodescricao Get_FieldNumber CADIMP.ESTACAO to icampoestacao Move (fnewfile()) to ifile // Função insegura para chamadas concorrentes... Open "CADIMP" as ifile Clear ifile Set_Field_Value ifile icampoid to iid Set_Field_Value ifile icampocaminho to scaminho

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 13 Set_Field_Value ifile icampodescricao to sdescricao VFind ifile 2 EQ Get_Field_Value ifile icampoid to iidfile Get_Field_Value ifile icampocaminho to scaminhofile Get_Field_Value ifile icampodescricao to sdescricaofile If ((Found) and iid = iidfile and scaminho = scaminhofile and sdescricao = sdescricaofile) Begin Get_Field_Value ifile icampoestacao to sestacao Close ifile Function_Return sestacao // Fonte continua... Como proceder em um caso como esse? Nos casos onde é necessário o uso de "Open as" deverá se optar entre dois métodos de uso. O primeiro é a reserva de Slots através do gerenciador de slots de orecursosglobais. E o outro é por meio do uso de objetos da classe cslottabeladinamica. Usando orecursosglobais Com Gerenciador de Slots Entre as muitas funções de orecursosglobais está o gerenciamento dos slots vagos do FileList que estão sendo usados em tempo de execução pela aplicação. Esse gerenciamento centralizado impede que haja conflitos no uso dos slots livres. Seguindo a necessidade do exemplo dado anteriormente, mostraremos a solução por meio do gerenciador de slots de orecursosglobais. // CADIMP.RV Conteúdo Integer icampoid icampocaminho icampodescricao icampoestacao Integer iid iidfile String scaminho sdescricao scaminhofile sdescricaofile sestacao Handle harquivo Get Value of (ID(Self)) to iid Get Value of (Caminho(Self)) to scaminho Get Value of (Descricao(Self)) to sdescricao Get_FieldNumber CADIMP.ID to icampoid Get_FieldNumber CADIMP.CAMINHO to icampocaminho Get_FieldNumber CADIMP.DESCRICAO to icampodescricao Get_FieldNumber CADIMP.ESTACAO to icampoestacao Get ReservarSlotLivre of (orecursosglobais(self)) to harquivo Open "CADIMP" as harquivo Clear harquivo Set_Field_Value harquivo icampoid to iid Set_Field_Value harquivo icampocaminho to scaminho Set_Field_Value harquivo icampodescricao to sdescricao VFind harquivo 2 EQ Get_Field_Value harquivo icampoid to iidfile Get_Field_Value harquivo icampocaminho to scaminhofile Get_Field_Value harquivo icampodescricao to sdescricaofile If ((Found) and iid = iidfile and scaminho = scaminhofile and sdescricao = sdescricaofile) Begin Get_Field_Value harquivo icampoestacao to sestacao Close harquivo Send LiberarSlot of (orecursosglobais(self)) harquivo Function_Return sestacao // Fonte continua... Como você pode notar a função ReservaSlotLivre de orecursosglobais tem como retorno um handle para um slot livre que a aplicação pode utilizar. Esse handle deve ser utilizado como manipulador da cópia que você criou e deve ser liberado 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

14 Fascículos do Desenvolvedor no final da tarefa. Para liberar esse manipulador no gerenciador nós usamos LiberarSlot de orecursosglobais. Só chame LiberarSlot após a chamada do comando Close. Usando cslottabeladinamica Para Simplificar a Consulta Como você pode notar no exemplo anterior, o uso do gerenciador de slots serve apenas para assegurar a segurança, mas não simplificam o processo em si. Para que houvesse uma simplificação do processo, foi desenvolvido a classe cslottabeladinamica. O uso de objetos cslottabeladinamica é feito para se simplificar todos os processos envolvidos, desde o uso do slot até ao acesso aos dados. O exemplo abaixo demonstra o uso de cslottabeladinamica. Compare e veja o número de variáveis e complicações que se reduz no uso dele. // CADIMP.RV Conteúdo Integer iid String scaminho sdescricao sestacao Handle hcstdcadimp Get Value of (ID(Self)) to iid Get Value of (Caminho(Self)) to scaminho Get Value of (Descricao(Self)) to sdescricao Get Create U_cSlotTabelaDinamica to hcstdcadimp Send CriaTabelaTemporaria to hcstdcadimp "CADIMP" Clear (phtabela(hcstdcadimp)) Set_Field_Value (phtabela(hcstdcadimp)) (Campo(hcstdCadImp, "ID")) to iid Set_Field_Value (phtabela(hcstdcadimp)) (Campo(hcstdCadImp, "CAMINHO")) to scaminho Set_Field_Value (phtabela(hcstdcadimp)) (Campo(hcstdCadImp, "DESCRICAO")) to sdescricao VFind (phtabela(hcstdcadimp)) 2 EQ If ((Found) and (iid = (CampoValorCorrente(hcstdCadImp, "ID")) ; and (scaminho = (CampoValorCorrente(hcstdCadImp, "CAMINHO")) ; and (sdescricao = (CampoValorCorrente(hcstdCadImp, "DESCRICAO")))))) Begin Get CampoValorCorrente of hcstdcadimp "Estacao" to sestacao Send Destroy to hcstdcadimp Function_Return sestacao // Fonte continua... Conforme demonstrado nessa situação ilustrativa, cslottabeladinamica se encarrega de todos os processos envolvidos, eliminando a necessidade de você ter de se preocupar com o slot em si e com outros dados como a numeração dos campos da tabela. O procedimento CriarTabelaDinamica é responsável por reservar o slot e reunir os meta-dados referente ao nome das colunas. A propriedade phtabela contém o manipulador do slot reservado. A função Campo retorna o número do campo conforme a string passada. Por fim, a função CampoValorCorrente retorna o valor do campo informado. Após ser utilizado, o objeto deve ser destruído o quanto antes. Durante a destruição, a classe se encarrega de liberar o slot e fechar a tabela. Atenção: Não chame o comando Close para fechar um slot aberto por cslottabeladinamica jamais. Nota A classe cslottabeladinamica possui uma série de usos não alistados aqui. Explicações mais detalhadas e específicas podem ser encontradas nos comentários do arquivo classes.pkg.

Apêndice I Recomendações Para um Bom Fonte Segue abaixo sete recomendações que se forem seguidas com afinco combinadas com criatividade o farão não somente um programador, mas sim um Desenvolvedor. 1. Não escreva longos procedimentos. Um procedimento não deve ter mais de dez ou doze linhas, deve ser escrito para ser reutilizável para mais de uma situação e deve evitar afetar valores globais. 2. Todo procedimento deve ter uma finalidade clara. A finalidade de um procedimento não pode ser mesclada com a finalidade dos procedimentos que vem antes ou depois dele. Um bom programa é uma série de procedimentos limpos que não se sobrepõe um ao outro. 3. Não use características muito complexas da linguagem. Se o seu trabalho não é feito com simples declarações de variáveis, chamadas de procedimentos, classes, declarações de controle de fluxo e operadores aritméticos, alguma coisa está errada. Quando você usa os recursos básicos da linguagem isso o faz pensar no que você está escrevendo. Não complique o que pode ser simples. 4. Nunca use recursos da linguagem que você não tem certeza como se comportarão. Se você costuma escrever código que você não tem certeza como se comporta, é melhor reavaliar em que área você quer trabalhar. 5. Evite ao máximo usar Copiar & Colar, principalmente se você é um principiante. Assim você usará o menor número de arquivos possíveis. 6. Evite usar referências a valores abstratos cuja origem pode ser desconhecida e o valor incerto (buffer, variáveis globais). 7. De tempos em tempos tente entender como as bibliotecas que você usa funcionam. Procure ver porque determinados processos são de um modo específico. Em suma, essas recomendações podem parecer genéricas, mas tente vê-las de um modo prático ao cumprir com seu dever. Siga um padrão claro Há muitos erros escandalosos em Visual DataFlex que podem ser encontrados em fontes de Desenvolvedores conceituados, mas isso não significa que o erro deles deve ser o nosso. Vamos considerar alguns erros básicos de programação que devem ser evitados. O Desenvolvedor deve sempre levar em mente ao escrever cada linha de código. Essa linha deve ser clara e inteligível. O fonte final deve estar asseado aparentando ordem e esmero, devidamente posicionados para melhor compreensão. Será que essa linha é realmente necessária? Existe alguma forma de simplificar o que eu estou escrevendo agora? Nunca poupe linhas que significarão cem linhas a menos no futuro e eliminarão possíveis bugs, mas nunca escreva mais linhas de código para obter trinta minutos a menos de trabalho. Lembre-se que cada linha que você escreve no seu fonte é mais uma chance de você estar inserindo um novo bug no seu projeto. Dadas as recomendações teóricas, segue abaixo algumas recomendações práticas em VDF. Sempre use notação matemáticas em declarações de controle de fluxo e condicionais ao invés de expressões verbosas antigas do VDF. Apenas em útimo caso use essas expressões verbosas (ex, constraint), já que elas dificultam a compreensão do fonte.

16 Fascículos do Desenvolvedor versão 1.6.1 Assim, evite sempre que possível o uso de EQ, GE, GT, LE, LT e NE. Ao invés disso use sempre que possível <, <=, =, not, <>, >= e >. (Ao usar esses operadores você será obrigado a usar parênteses, o que torna o fonte ainda mais claro.) Verifique sempre se não é possível resumir a uma linha uma condição if... else de duas linhas. Em muitos casos isso é plenamente possível com a chamada expressão ternária. Por exemplo, veja o fonte abaixo. If (CADPRO.DESCONTO_OK = "S") Move idesconto to ESTMOV.DESCONTO Else Move ivalor to ESTMOV.DESCONTO Embora o VDF não possua um operado ternário nativo, é possível criar uma expressão ternária usando a função If. Move (If((CADPRO.DESCONTO_OK = "S"), idesconto, ivalor)) to ESTMOV.DESCONTO Como você pode ver, a expressão abaixo é compacta e bem clara para entender, poupando uma linha para a visão de um programador que procura entender o fonte. Outro caso é quando estamos decidindo se atribuímos verdadeiro ou falso a algum elemento. Nesses casos, não há necessidade de se usar IF... Else. Por exemplo, note o código abaixo. If (CADPRO.DESCONTO_OK = "S") Set Visible_State of odesconto to True Else Set Visible_State of odesconto to False Em um caso como esse é desnecessário usarmos duas linhas. Nós poderiamos declarar isso simplesmente assim. Set Visible_State of odesconto to (CADPRO.DESCONTO_OK = "S") Evite operadores desnecessários. Como nós sabemos, o VDF é uma linguagem em si verbosa que possui certos operadores como os parênteses, Begin e que são desnecessários em certas circunstâncias. A menos que eles realmente contribuam para um melhor entendimento do fonte, evite-os. Veja um caso de uso desnecessário abaixo. If (CADPRO.DESCONTO_OK = "S") Begin Move idesconto to ESTMOV.DESCONTO O código abaixo deveria ser simplesmente assim: If (CADPRO.DESCONTO_OK = "S") Move idesconto to ESTMOV.DESCONTO Tenha uma linha de raciocínio clara sobre o seu propósito. Em alguns casos, programadores simplesmente complicam demasiadamente o código com linhas em excesso onde algumas nem serão executadas. Obviamente, para evitarmos que isso aconteça, precisamos primeiro escrever essas linhas por nós mesmo, nunca copiar e colar. Depois de escrever, tente ver se não tem como dizer a sua lógica de um modo mais direto. Veja o exemplo abaixo. Integer iret // No Final da Função... Get YesNoCancelBox "Tem certeza mesmo?" "Atenção" 1 To iret If (iret = MBRYes) Begin // Faz alguma coisa... Function_Return True Else if (iret = MBRNo) Function_Return False Else if (iret = MBRCancel) Function_Return False Function_Return Nesse exemplo, há três erros presentes no fonte. Primeiro, o programador usou um YesNoCancelBox para uma situação em que um YesNoBox seria o suficiente, já que ele trata o resultado do Cancelar da mesma forma que ele trata o Não. Segundo, todos esses condicionais poderiam ser resumidos em uma única linha. Terceiro, não é necessário um Else para chamar um Function_Return ou um Procedure_Return quando a sentença condicional é a ultima sentença do método em questão. Corrigindo esse código, o formato mais simples e direto seria o seguinte.

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 17 // No Final da Função... If ((YesNoCancelBox("Tem certeza mesmo?", "Atenção")) // Faz alguma coisa... Function_Return True Function_Return False Function_Return = MBRYes) Begin Não crie validações em campos de entrada de dados que impeça os usuários de sair deles até digitar o dado correto. Em tais procedimentos de validações ao sair do campo, caso seja retornado o valor 1, o usuário é impedido de sair do campo. Isso é um erro de layout crasso. Não cometa esse erro. Caso você precise validar um dado quando o usuário sair de um campo, faça de um modo que não afete o fluxo de uso da aplicação. Por exemplo, limpe o valor inválido do campo, altere algum label que sirva como status, coloque a cor de fundo do campo para vermelho, porém nunca exiba uma caixa de diálogo como resposta e muito menos impeça o usuário de abandonar o campo. Por ultimo, como um bom Desenvolvedor VDF, entenda como o buffer do arquivo de dados funciona em conjunto com o DDO e use-os de acordo. Esse é um problema latente entre programadores VDF, mas uma breve explicação será fornecida aqui. Todo arquivo de dados em VDF pode ser acessado por um canal chamado de buffer do arquivo. Quando nós acessamos os dados de uma tabela usando apenas o nome da tabela e o nome da coluna (ex,stop_box CADPRO.MATRICULA), nós estamos na realidade lendo o buffer desse arquivo de dados diretamente. Nas primeiras versões do VDF, essa técnica era satisfatória, entretanto quando é necessário ler e alterar vários registros da mesma tabela em várias telas simultaneamente, o uso de um buffer que só pode direcionar um registro por vez para várias tarefas simultâneas pode ser desafiador. Isso porque o buffer só direciona um registro por vez e ele é um só para toda a aplicação. A fim de suprir essa deficiência, foi provido o DD ou Dicionário de Dados, que nada mais é do que uma classe de objetos que usam o buffer para armazenar os dados de um registro específico. Assim, com o uso de objetos DD ou DDOs nós podemos ter um DDO apontando para o registro 20 enquanto o buffer está apontando para o registro 10. Em um caso desses, se eu usar os comandos do buffer para acessar os dados da tabela eu vou ter os valores do registro 10, enquanto se eu usar as funções do DDO para ler os dados da tabela, eu vou ter os valores do registro 20. Com tal forma de organização eu posso ter vários DDOs apontando para vários registros da mesma tabela sem precisarem se importa para onde o buffer está direcionado, se é que este está apontando para algum registro. O DDO consegue cumprir esse papel por copiar todos os valores do registro para dentro de sua estrutura. À medida que o usuário altera esses valores, o DDO mantém um registro das alterações. Ao receber a ordem de salvar o registro, o DDO localiza o registro novamente no buffer e copia todos os dados alterados para o buffer e os salva no arquivo usando comandos para gravação de dados via buffer. Os problemas relacionados ao uso de buffer e DDOs começam a partir do momento que alguns programadores não entendem esse fato, e também não compreendem que embora o buffer não afete a posição de um DDO, o DDO afeta a posição de um buffer porque, no final das contas, o DDO usa o buffer para ler, criar, alterar e deletar registros. A seguinte ilustração mostra quatro DDOs apontando para quatro registros diferentes da tabela X e a relação que eles têm com o buffer dessa tabela. 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

18 Fascículos do Desenvolvedor versão 1.6.1 DDO A - 20 DDO B - 100 Buffer X - 10 DDO C - 12 DDO D - 30 Em lugares onde se usam DDOs, mesmo que seja apenas um DDO, deve-se sempre evitar usar o buffer ou valores nele, a menos que realmente a intenção seja buscar valores que estão na tabela sem afetar os valores que estão no DDO. Também, no caso de telas guiadas por DDOs, ou os chamados objetos visuais DEO, os controles que exibem dados da tabela geralmente usam DDOs e tem os seus valores alterados por eles. Assim, nunca se usa a propriedade Value de um controle DEO para alterar os valores do registro corrente apontado pelo DDO. Ao invés disso, use recursos do próprio DDO para esse fim (ex Get_Field_Current_Value, Set_Field_Changed_Value, etc). Por exemplo, nunca faça como no seguinte código. Object CadPro_DD is a CadPro_DataDictionary _Object Object CadPro_Desconto is a dbform Entry_Item CADPRO.DESCONTO _Object Procedure AtualizarDesconto Number ndesconto If (Value(CadPro_Desconto(Self)) = 0) Set Value of (CadPro_Desconto(Self)) to ndesconto _Procedure Embora o controle CadPro_Desconto represente o campo CADPRO.DESCONTO para o DDO CadPro_DD nesse exemplo, atribuir o valor ou buscar o valor a partir da propriedade Value desse controle significa passar por uma rota muito longa até chegar ao lugar original da informação. Isso diminui a perspectiva de segurança da aplicação, já que podem ser inseridos processo inesperado nesse caminho. Seria também um grande engano usarmos algo semelhante ao exemplo seguinte. Procedure AtualizarDesconto Number ndesconto Move (CADPRO.VALOR ndesconto) to ndesconto // fonte continua... _Procedure Nesse exemplo, o erro está sendo o acesso direto ao buffer, que pode estar direcionado para outro registro, ou mesmo que esteja no mesmo registro, pode não estar refletindo o valor correto devido alguma atualização no valor que ainda não foi salva no buffer. Este é um erro mais grosseiro ao código que pode significar bugs sérios já que nem sempre algum problema é prontamente observado. O próximo exemplo demonstra qual é o acesso correto aos dados de um registro mantido em DDO. Object CadPro_DD is a CadPro_DataDictionary _Object Object CadPro_Desconto is a dbform Entry_Item CADPRO.DESCONTO _Object Procedure AtualizarDesconto Number ndesconto

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 19 Number nvalue Get Field_Current_Value of (CadPro_DD(Self)) Field CADPRO.DESCONTO to nvalue If (nvalue = 0) Set Field_Changed_Value of (CadPro_DD(Self)) to ndesconto _Procedure Como você pode ver, o acesso e a alteração são feitos diretamente no DDO. Não se preocupe que o DDO se encarregará de atualizar o valor do controle. Em alguns treinamentos é dito que nunca se deve usar o buffer. Como você pode ver essa é uma afirmação enganosa. Mais informação será preparada sobre esse tema, mas procure entender corretamente essas práticas seguras para que você possa manipular tanto buffer quantos DDOs como uma ferramenta ao seu favor, não um pesadelo. Desfrute Do Seu Trabalho Esforce-se em seguir essas sugestões. Qualquer esforço nesse respeito beneficiará primariamente você como desenvolvedor. Lembre-se que seu trabalho será verificado e visto por outros várias vezes. O legado que você deixa em uma base de código pode ser duradouro. Esforce-se em ser lembrado como alguém inteligente, prático e organizado. Isso lhe poupará dores de cabeça em ter que corrigir seu próprio código outras vezes, ou lhe poupará ainda a vergonha de não consegui explicar para outro Desenvolvedor como o seu próprio código funciona. Esteja determinado em transformar o seu trabalho em uma fonte de alegria. 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

Apêndice II Ativação e Desativação de Janelas O Método Sugerido O mecanismo de Ativação e Desativação tem um longo histórico. Ele foi construído como parte da original Interface de usuário orientada a objetos e foi submetido a muitas mudanças. Teve de ser estendido para suporta objetos modal e modeless. Após isso foi expandido para trabalha com objetos orientados por dados (DEOs). Mais tarde, ele foi alterado para suportar controles do Windows. Não surpreende que o resultado final seja uma variedade de formas de fazer as coisas funcionarem e mais outros muitos modos de fazer as coisas não funcionarem. Mais cedo ou mais tarde, todo mundo acaba esbarrando em alguma questão sobre ativar e desativar diálogos. O propósito desse artigo e prover uma série de orientações para o processo de ativação e desativação. Você verá os meios mais simples e consistentes para controlar esse processo. Você saberá quais mensagens você deve enviar e quais você deve complementar. Você também verá quais você deve deixar sozinhas e isso pode te surpreender. Não serão abordados todos os métodos de ativação e desativação e talvez você conheça outro procedimento. Porém, será explicado bastante a respeito do processo a fim que você possa trabalhar mais eficientemente independente do método que você escolha. Vamos dar a definição de alguns termos. Um diálogo é um diálogo do Windows. Uma view é um diálogo modeless como um dbview ou um View. Um diálogo modal é um diálogo modal como um dbmodalpanel ou um ModalPanel. A classe determina se o diálogo é modal ou modeless. Você não pode transformar uma view em modal e você não pode transformar um diálogo modal para modeless. Um objeto DEO é um objeto orientado a dados que trabalha com base na estrutura de Dicionário de Dados / Objeto de Entrada de Dados (DD/DEO). Um objeto DEO pode ser um container ou um controle. Exemplos de containers DEO são dbview, dbmodalpanel e dbcontainer3d. Exemples de controles DEO são dbform e cdbtextedit. Um objeto non-deo é um objeto que não compreende a estrutura DD/DEO. Exemplos de containers non-deo são View, ModalPanel e Container3D. Exemplos de controles non-deo são Button, Form e ctextedit. Um diálogo DEO é um diálogo que compreende a estrutura DD/DEO. Um diálogo DEO pode conter uma mistura de objetos DEO e non-deo. Um diálogo non-deo pode conter apenas objetos non-deo. Ativação se refere um diálogo que não está que ainda não foi desenhado. Um diálogo está inativo quando não está sendo exibido e ativo quando passa a ser exibido. O objeto Foco é o objeto que possui o foco de entrada. Mudança de Foco se refere a troca de foco entre objetos ativos. Isso pode ocorrer dentro de um diálogo ou através de diálogo. Freqüentemente o termo ativar é usado para referir-se a ativação ou a mudança de foco. Nesse artigo, ativar referese somente a ativação. Desativação significa fechar o diálogo e torná-lo inativo. Ativação Do ponto de vista do usuário a ativação torna o diálogo visível e disponível para uso. De uma perspectiva técnica, a ativação cria e exibe o objeto diálogo do Windows e todos os objetos filhos dentro do diálogo, coloca-os na árvore de foco do DataFlex, e da o foco a um desses objetos. A propriedade Activate_State determina se um objeto já está ativado, indicando se ele já esta na árvore de foco. A propriedade Windows_Handle determina se um controle do Windows foi criado. Normalmente estas duas propriedades

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 21 devem mudar em conjunto. Se um objeto está na árvore de foco, Activate_State deverá ser true e Windows_Handle diferente de zero. A propriedade Focus determina qual objeto tem o foco. O processo de ativação é um pouco diferente entre views e diálogos modais. Enquanto muito do comportamento é similar há algumas diferenças sérias. Começaremos com as views. Ativação de Views A ativação da view pode ser representada com esse pseudocódigo. Esse código assume que a que a view ainda não está ativa (essa é uma ativação e não uma mudança de foco). Activate_View Activate Add_Focus Page_Object (objeto adicionado a árvore de foco) Activating Page (Controle do Windows criado) Broadcast Add_Focus (Para todos os filhos) (Dá o foco para o primeiro objeto que possa receber foco) Activate_View é a mensagem que você deve enviar para ativar a view. Na verdade, é a mensagem Activate que executa a ativação. Ela é uma mensagem útil e importante e será discutida em breve. Add_Focus cria o controle do Windows e o adiciona a árvore de foco. Ele faz isso por enviar Page_Object, o qual coloca o objeto na árvore de foco, chama o evento Activating e chama Page, o qual cria o controle do Windows. Então, Add_Focus envia Add_Focus para todos os controles filhos. Finalmente Activate moverá o foco para o primeiro objeto filho que o receba. Isso é feita enviando Activate para o objeto (nesse caso activate é usado para mudança de foco). Do ponto de vista de customizações de view, nós só estamos interessados em duas mensagens: Activate e Activating. A Mensagem Activate Você nunca precisará enviar a mensagem Activate a fim de realizar a ativação. Porém, essa é uma mensagem muito útil para complementos. Se você deseja cancelar a ativação, complemente e não encaminhe (forward) a mensagem. Se você deseja faze alguma mudança no diálogo antes da ativação, você pode fazê-la antes de encaminhar a mensagem por que na verdade o processo não foi iniciado ainda. Lembre-se que o método Activate é usado para ativação e mudança de foco. Se você desejar que suas alterações sejam usadas pelas tarefas corretas, use Activate_State para determinar isso. Segue um exemple do como isso pode ser feito. Procedure Activate Returns Integer Boolean bactivate bcanactivate Integer iret Get Activate_State to bactivate // Se for usado para ativação IF (not(bactivate)) Begin // chama um método local para determinar se a ativação é permitida. Get CanActivate to bcanactivate IF (not(bcanactivate)) Begin Procedure_Return 1 // Chama um método local para efetuar outras operações locais antes // de começar Send PreActivateDialog Forward Get Msg_Activate to iret Else Begin // Se for usado para mudança de foco Forward Get Msg_Activate to iret Procedure_Return iret _Procedure 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

22 Fascículos do Desenvolvedor versão 1.6.1 A função CanActivate e PreActivateDialog são exemplos e não existem você teria de criá-las. Agora nós temos um ponto muito importante. Uma vez que você encaminha Activate para o sistema de classes, você ultrapassou uma linha sem volta e a janela será ativada. Se a ativação é interrompida a partir desse ponto, isso é considerado um erro de programação e as coisas não vão ficar boas. Você pode complementar após ter encaminhado a mensagem Activate, mas você só poderá fazer isso com views e não com diálogos modais (será explicado em breve). Nesse ponto a view está ativada e um objeto dentro da view tem o foco. Você pode alterar outros objetos por mudar propriedades ou até mesmo o foco enviando Activate para outro objeto dentro do diálogo. Note que embora você nunca deva enviar Activate para realizar ativação, você pode enviá-lo para mudança de foco. O Evento Activating Activating é chamado por cada objeto no diálogo em uma ordem do topo para baixo. Ele é chamado antes que o objeto do Windows seja criado. Também é chamado antes que os controles filhos sejam criados (ele é chamado antes que Add_Focus seja enviado para os objetos filhos). Portanto, nesse ponto você pode mudar propriedades, mudar os estilos do Windows e fazer até mesmo alterações mais agressivas aos objetos filhos. Você não deve tentar fazer qualquer coisa que mude o foco, desative objetos ou altera a arvore de foco existente. Você não pode usar essa mensagem para cancelar a ativação ela não foi criada para isso. Portanto, não retorno um valor de dentro desse evento. Ativação de Diálogo Modal A ativação do diálogo modal é quase a mesma que a da view, mas há algumas diferenças chaves. Você ativa um diálogo modal por enviar a mensagem Popup. Ela faz o seguinte. Popup Activate Create_Dialog (Diálogo do Windows criado!) ---Um novo nível da interface do usuário é criado--- Add_Focus Page_Object (objeto adicionado a árvore de foco) Activating Page (Controle do Windows criado) Broadcast Add_Focus (Para todos os filhos) (Dá o foco para o primeiro objeto que possa receber foco) A principal diferença aqui é que Create_Dialog é chamada entre Activate e Add_Focus. Isso força o comportamento modal por desabilitar os objetos origens e iniciar um novo nível de IU. Iniciar um novo nível de IU significa que o procedimento Create_Dialog não está completo até que o diálogo modal esteja fechado. Isso muda completamente o comportamento em relação ao complemento posterior na mensagem Activate. O que foi posto posteriormente não é executado até que o diálogo feche. Sendo assim, não use complementos posteriores na mensagem Activate. Entretanto, você ainda pode usa Activate para os mesmo pré-complementos usados na ativação de uma view. Há outra diferença técnica. Por razões internas, o controle Windows do diálogo modal é criado em Create_Dialog antes que Add_Focus seja chamado. Isso significa que o controle Windows já existe quando Activating é chamada e, portanto Page não precisa criar esse controle. Normalmente isso não muda nada, mas se você precisar fazer alguma coisa com o controle diálogo exterior antes de ele ser criado, você deve fazer isso no Activate. Somente o controle diálogo é criado prematuramente todos os filhos do diálogo modal são criados segundo o modelo normal. Talvez você notou que nós não usamos Popup_Modal para ativação. Essa mensagem funciona mas não é necessária. Popup_Modal é uma mensagem herdada que chama Popup. Mudança de Foco Você nunca deve precisar usar Activate para ativar um diálogo. Você pode enviar Activate para mudar o foco. Isso é feito com freqüência dentro de uma view ou de um diálogo modal quando se muda o foco de um objeto para outro. Ao mudar o foco entre views, é recomendável que você trate isso como uma mudança de view. Primeiro ative a view e, se necessário,

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 23 envie Activate para um objeto dentro da view. Lembre-se que a mudança de foco ocorre quando o Activate_State da view está apontado para true. Desativação Desativação é o processo de fechar um diálogo ativo. Da perspectiva do usuário a view está fechada quando ela não está mais visível e utilizável. Internamente, o diálogo e todos os seus filhos são removidos da árvore de foco do DataFlex, todos os objetos do Windows no diálogo são destruídos e o foco é movido para alguma outra parte da aplicação. Diferente do processo de ativação onde views e diálogos modais se comportam de maneiras diferentes uns dos outros, o processo de desativação para esses dois tipos de diálogo são iguais. Contudo, há algumas diferenças significantes entre os diálogos DEO (dbview, dbmodalpanel) e os non-deo (View, ModalPanel). Desativação e Diálogos DEO Começaremos com os diálogos DEO porque esses são usados mais freqüentemente. Close_Panel Exit_Function Request_Cancel Verify_Exit Executa a mensagem Verify_Exit. Se retornar zero, continua. Deactivate Send Activate para outro diálogo (mudança de foco) Release_Focus (Libera o foco) Broadcast Release_Focus (Para todos os filhos) Remove_Object (Remove o objeto da árvore de foco) Deactivating Page_Delete (Destrói os controles do Windows) Como você pode ver, esse processo é um pouco complicado e na verdade ele é bem mais complicado. Portanto, nós começaremos com a parte simples. Eis o que você precisa saber para controlar a desativação. 1. Envie Close_Panel para fechar um diálogo. Você pode enviá-lo para o diálogo ou qualquer controle dentro dele. 2. Crie a sua própria função pode-fechar que retorna diferente de zero para cancelar a desativação. Coloque o id de sua mensagem na propriedade Verify_Exit_Msg do objeto diálogo. 3. Use o evento Deactivating para controlar qualquer lógica está fechando. Deactivating é enviado para cada objeto no diálogo. 4. Não complemente ou envie qualquer uma das outras mensagens. Se você seguir esses passos, você não terá de se preocupar com as complicações que serão descritas. A principal complicação é que os objetos DEO tenta fazer coisas demais. Você talvez ache que todas essas mensagens (Close_Panel, Exit_Function, Request_Cancel, etc) são todas definidas e manipuladas pelo objeto diálogo via delegação. Com objetos DEO filhos não é assim. Cada classe DEO entende e manipula essas mensagens diretamente. Para piorar as coisas, esses objetos podem enviar diferentes mensagens para fechar o diálogo (Close_Panel, Exit_Function ou Request_Cancel). Para criar mais uma complicação, objetos non-deo (como botões) não entendem essas mensagens e, portanto as delegam. Isso torna difícil saber qual mensagem deve ser complementada. Dependendo de onde o foco está mensagens para fechar deferentes estarão sendo enviadas para diferentes objetos. A boa noticia é que se você não complementar nenhuma dessas mensagens, tudo isso irá funcionar. Enquanto você usar sua função pode-fechar no Verify_Exit_Msg do diálogo, você terá um comportamento consistente. A mensagem Verify_Exit passa pelos DEOs de origem procurando por um Verify_Exit_Msg diferente de zero. Se você colocar Verify_Exit_Msg no diálogo externo, todos os objetos o encontrarão e usarão a mesma função pode-fechar. Como exemplo, adicionar o seguinte código a uma dbview ou a um dbmodalpanel apenas lhe permitiria fechar o diálogo quando a data corrente tivesse com o segundo impar (uma técnica massa que deixa qualquer um louco). Object odbawaremodaldialog is dbmodalpanel Set Label to Label... Set Size to 89 211 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

24 Fascículos do Desenvolvedor versão 1.6.1 Set Border_Style to Border_Thick Function CancelClose Returns Boolean DateTime ddt Integer isec Boolean bstopit // teste inútil que retorna true para parar a desativação // se o valor corrente dos segundos for par. Move (CurrentDateTime()) to DDT Move (DateGetSecond(dDT)) to isec Move (Integer(iSec/2) = (isec/2.0)) to bstopit Function_Return bstopit _Function Set Verify_Exit_Msg to (RefFunc(CancelClose)) Desativação e diálogos non-deo A desativação de um diálogo não DEO é muito mais simples. Uma vez que não é permitido aninhar objetos DEO dentro de containers non-deo, nós sabemos que nenhum desses objetos são DEOs. Deactivation se parecerá com o seguinte. Close_Panel Deactivate Send Activate para outro diálogo (mudança de foco) Release_Focus (libera o foco) Broadcast Release_Focus (Para todos os filhos) Remove_Object (Remove o objeto da árvore de foco) Deactivating Page_Delete (Destrói os controles do Windows) Assim como em diálogos DEO, você envia Close_Panel para desativar o objeto. Neste caso, enviar Close_Panel para qualquer objeto no diálogo resultará que a mensagem seja delegada ao objeto diálogo. Se você deseja cancelar a desativação, complemente Close_Panel e não encaminhe a mensagem. Eis um exemplo de como cancelar a desativação de um diálogo non-deo. Object odbawaremodaldialog is ModalPanel Set Label to Label... Set Size to 89 211 Set Border_Style to Border_Thick Function CancelClose Returns Boolean DateTime ddt Integer isec Boolean bstopit // teste inútil que retorna true para parar a deseativaçao // se o valor corrente dos segundos for par. Move (CurrentDateTime()) to DDT Move (DateGetSecond(dDT)) to isec Move (Integer(iSec/2) = (isec/2.0)) to bstopit Function_Return bstopit _Function Procedure Close_Panel Booleand bstop Get CancelClose to bstop If not bstop Begin Forward Send Close_Panel _Procedure

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 25 O processo de desativação Uma vez que a desativação foi iniciada (que a mensagem Deactivate foi enviada) o processo é o mesmo para todos os diálogos. Se a desativação já foi iniciada ela não pode ser interrompida e se for, é um erro de programação e a aplicação não será estável. A mensagem Deactivate funciona de dois modos. Ela é usada para encontrar o objeto da área externa para desativá-lo e então ela é usada para desativar um objeto. Você tem de saber como enviar essa mensagem com os parâmetros corretos e você tem que saber como complementá-la da maneira correta. Então esqueça! Não a envie nem a complemente. Quando você fecha um diálogo você deseja ter certeza que há algum outro lugar para receber o foco. Com views, dificilmente isso é um problema. Com diálogos modais, o sistema tentará dar o foco ao objeto que tinha o foco quando o diálogo modal foi chamado. Se por alguma razão esse objeto não puder retomar o foco, isto é um erro de programação e o programa não será estável. Objetos filhos são desativados antes de o objeto origem ser desativado. O evento Deactivating é enviado para cada objeto ativo no diálogo em uma ordem debaixo para cima. Você não pode usar esse evento para cancelar a desativação. Quando a desativação é chamada, o objeto já foi removido da árvore de foco (active_state é igual a zero) mas o controle do Windows ainda existe (Window_Handle é diferente de zero). Alem disso, todos os objetos filhos já estão desativados (removidos da árvore de foco e os controle do Windows destruídos). O método Page_Delete na verdade destrói os controles do Windows. Se você complementar o código de Deactivating, será mais provável que você faça isso somente no objeto diálogo. Trabalhando com Diálogo Modal Diálogos modais são modais por uma razão. Você deseja chamá-los em um momento em particular, e suspender o resto da aplicação até que o processo deste diálogo modal o forneça uma informação que você precisa para continuar. Enquanto você poderia usar algumas das mensagens que nós abordamos aqui tais como Popup e Deactivating para manipular pré- e pós-processamento, isso geralmente não é a melhor estratégia. Veja o artigo Comunicação entre Views e Diálogos (http://support.dataaccess.com/forums/blog.php?b=30, em inglês) para uma discussão cabal deste tópico e um método sugerido. Como as coisas dão errado Várias vezes foi mencionado que coisas ruins acontecem quando a ativação ou a desativação não são corretamente concluídas. Há três coisas que devem ser corretamente sincronizadas para que tudo funcione. Essas são a árvore de foco, os objetos do Windows e o nível de IU. A árvore de foco é uma estrutura do DataFlex que controla como a navegação para o objeto seguinte e anterior se dará. Objetos são adicionados e removidos dessa árvore de foco durante ativação e desativação. Objetos do Windows são objetos que são controles que são criados durante ativação e destruídos durante a desativação. Quando um objeto é adicionado a arvore de foco, um objeto do Windows deve ser criado e vice-versa. Quando a ativação ou a desativação são derrubadas impropriamente, você pode acabar em uma condição onde um objeto está na árvore de foco, mas não existe nenhum controle do Windows, ou o objeto não está na árvore de foco mas o controle do Windows existe. Você pode testar isso por olhar Active_State, que reflete o status da árvore de foco, e Window_Handle que indica se o controle do Windows existe. O nível da IU só é importante com diálogos modais. O nível da IU é o nível onde o loop de processamento da interface do usuário DataFlex é executado. Normalmente há apenas um nível que é usado por todas as views. Quando um diálogo modal é ativado, o método Create_Dialog cria um novo nível de IU e suspende o nível anterior. O nível de IU permanece suspenso até que o novo nível seja finalizado, o que ocorre durante a desativação. Se alguma coisa der errado durante a desativação, o nível de IU pode não finalizar. Quando isso acontece o diálogo pode até parecer estar fechado, mas você estará processando eventos de IU no nível de IU errado. Você pode ver isso com o depurador. Pause o seu programa. Se o diálogo parece fechado mas você ainda vê Create_Dialog no Call-Stack, você tem um problema para resolver. Nesse ponto há uma grande chance que Active_State e Window_Handle não estejam mais sincronizados. 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.

26 Fascículos do Desenvolvedor versão 1.6.1 Em todos os casos citados, uma vez que não há sincronia entre Active_State e Window_Handle, não haverá um modo fácil de recuperar a execução da aplicação. Mesmo que as coisas pareçam funcionar, nada está funcionando corretamente. Normalmente você não precisa se preocupar com nada disso porque o processo de ativação e desativação do DataFlex se encarrega disso. Se você está tendo algum problema, você está fazendo alguma coisa errada. Corrija e tudo ficará perfeito.

Fascículos do Desenvolvedor Orientação Essencial em Práticas e Metodologias em Visual Dataflex 27 Escreva seu próprio futuro Todo Desenvolvedor pode escolher entre cumprir tarefas ou ter paixão pelo que faz, entre fazer o possível ou fazer o impossível, entre escrever um código ou escrever seu próprio futuro. Atualize suas habilidades como desenvolvedor por conhecer e aplicar Recursos e Idéias providos pelo Desenvolvimento da Atual Sistemas. Nós Queremos Te Ouvir Nós apreciaremos qualquer feedback a respeito desse material. Sua opinião e suas sugestões são muito relevantes e pode nos levar a construir conteúdos melhores. Sua participação será uma ajuda. Envie seu feedback para forumdev@atualsistemas.net. Equipe Editora Desenvolvido e Escrito Por Claudio M. Souza Junior Revisado e Editado Por Wanderson Lúcio Bastos 2011 Atual Sistemas. Todos os direitos Reservados. Ao fazer uso desse material você está automaticamente concordando com o termo de licença na página 3.