Anda di halaman 1dari 29

Manual do Desenvolvedor

Fascculo I
Junho/2011

Gerenciando a Abertura de Views,


ModalPanels e DataFiles Para Melhor
Desempenho

Esse documento uma obra intelectual de uso restrito da Atual Sistemas. Qualquer ato de leitura, alterao, cpia ou distribuio,
completa ou parcial deve ser feita somente sob autorizao expressa. A posse ou uso no autorizado desse documento, ou do seu
contedo completo ou parcial, constitui-se um uma violao direta dos direitos de intelectualidade e ser julgada conforme o rigor da lei.

ii

Fascculos do Desenvolvedor

Contedos
Trabalhando Com Janelas Visuais Deferred

Abrindo Tabelas No Momento Certo

Usando Comando Open As, Slots e Apoio dos Recursos Globais

12

Recomendaes Para um Bom Fonte

15

Ativao e Desativao de Janelas O Mtodo Sugerido

20

Captulo 1

Trabalhando Com Janelas Visuais


Deferred
Ao desenvolver aplicaes grficas, para que haja uma melhor interao entre Usurio-Software, se faz um extensivo uso de
Janelas. Janelas diferem entre si no somente em aparncia e contedo, mas principalmente em comportamento. Por isso,
muitas vezes um sistema requer um grande nmero de janelas. Em cada uma dessas janelas, h componentes e objetos que
compe o seu contedo e as tornam necessrias. Quando temos que lidar com um grande nmero 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 captulo aborda que recursos o Visual DataFlex nos dispes, bem como que recursos foram desenvolvidos pela prpria
Atual Sistemas, para que no venhamos a estar desperdiando recursos necessrios ao inserir novas janelas no sistema.

Como o Visual DataFlex Classifica Janelas


Seguindo o modelo utilizado no Visual DataFlex, ns podemos classificar janelas em duas categorias (h mais tipos de
janelas):

Modal Janelas modal so caracterizadas por no permitirem que o usurio selecione janelas que j foram abertas
anteriores a ela na mesma aplicao. Em Visual DataFlex ns usamos as classes ModalPanel e ReportPanel para
criar janelas modal, sendo a ultima classe usada apenas para relatrios.

Modeless Janelas modeless so usadas em casos quando no desejamos impedir que usurio faa outras tarefas
na aplicao enquanto essa janela est aberta. Em Visual DataFlex ns usamos as classes View e ReportView para
criar janelas modaless, sendo a ultima classe usada apenas para relatrios.
Dica

Consulte o apndice sob ttulo Ativao e Desativao de Janelas O Mtodo


Sugerido.

Ativao Atrasada de Janelas


Todos os objetos visuais que pertencem ao escopo (que esto dentro) do objeto Client_Area devem ser criados no regime
Deferred (efeito de criao atrasada). Isso significa que o contedo dessas janelas s ser criado quando elas forem ativadas
pela primeira vez. Isso evita o consumo desnecessrio de memria e reduz o tempo necessrio para iniciar a aplicao
Para tornar uma View ou ReportView deferred, troque o valor da propriedade Deferred Object para True, ou faa a
substituio do cdigo A pelo cdigo B seguindo as caractersticas do seu objeto.
//Cdigo A
Activate_View Activate_MeuRelatorio for MeuRelatorio
Object MeuRelatorio is a ReportView
// Restante do cdigo
End_Object

Troque o cdigo acima para


//Cdigo B
Deferred_View Activate_MeuRelatorio for ;
Object MeuRelaorio is a ReportView
// Restante do cdigo
Cd_End_Object

Fascculos 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 inicializao atrasada, nenhum de seus objetos filhos ser criado
at que voc chame o mtodo de disparo, no caso Activate para Views e ReportViews (Modeless) e Popup_Modal para
ModalPanels e ReportPanels (Modal). Isso significa que at que algumas dessas funes sejam chamadas, nenhuma
informao 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 dilogos modais envie Close_Panel para o componente segundo o nome dele.
Ateno: Ao passar um componente para deferred, no referencie objetos filhos de componentes modeless (ex:
ReportPanel, ModalPanel ...) usando o nome do componente no endereo. Por exemplo, caso voc tenha um
componente modeless chamado Consulta_SL que possui um objeto filho chamado Exata, no referencie esse objeto
com a seguinte sntese:
Send AlgumaCoisa to (Exata(Consulta_SL(Self)))

Nesses casos, no use o nome do componente visual. Ao invs 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 execuo 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 Necessrios Aps a Ativao da Janela


J que os dados de um objeto s ficam disponveis aps a sua criao, foram desenvolvidos e disponibilizados sistemas para
compartilhamento de dados que se comportem de maneira segura e adequada entre os mdulos visuais. Esses so o
Sistema de Parmetros Globais, Sistema de Registros Globais e o Gerenciador de Dados Mltiplos. Seguindo a ordem em que
foram alistados tente dar prioridade a eles. Caso o primeiro no seja suficiente, tente o segundo, se esse tambm no for
suficiente tente o terceiro. Portanto segue abaixo como resolver algumas das situaes, o que requerer criatividade do
programador na escolha apropriada.

SPG Quando necessrio passar um parmetro


Talvez uma informao que era definida antes da ativao de mdulo possa ser transformada em um parmetro no sistema
de recursos globais. Por exemplo: O ForBax tinha de abrir o ForExc em dois modos que diferiam no boto que o usurio
clicava para abrir o ForExc. Um dos botes era para consulta e, portanto tudo que estivesse relacionado com alteraes teria
que ser desabilitado a fim de que toda a tela se comportasse em modo somente leitura. O outro deveria permitir que o
usurio fizesse alteraes. Essa informao deveria estar disponvel para o dilogo durante a sua criao. Como resolver a
situao?
Foi inserido um parmetro no Sistema de Parmetros Globais. Ao ser aberto, o ForExc procura pelo parmetro. Caso ele seja
encontrado, se entende que a exibio deve ser em modo somente leitura. Durante a consulta se realiza a excluso do
parmetro j que ele ser consultado apenas uma vez durante a ativao do objeto visual.
O cdigo abaixo demonstra a criao do parmetro antes da ativao do dilogo.
// ForBax.vw cabealho
Use vdfclasses.pkg
Use ForExc.vw
// Dentro do ForBax...

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


//
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))
End
End_Procedure

Note que a constante que FOREXC_SOMENTE_LEITURA no est definida no arquivo FORBAX.VW, mas no FOREXC.VW j
que l que est o fonte a quem o parmetro se refere.
// ForExc.vw Cabealho.
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
End
Else Begin
Set Label of (ForExc(Self)) to "Excluso 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
End
Forward Send Activate
End_Procedure

Conforme voc pode notar, voc dever usar essas funes a partir do objeto oRecursosGlobais. Esse objeto deve ser
sempre usado com a finalidade do compartilhamento de dados globais entre views. Quanto a funo DeletarParametro ela
funciona de maneira idntica a funo ConsultarParametro, com a nica diferena que ela apaga o parmetro quando o
encontra. Caso o parmetro seja encontrado o retorno de ambas as funes ser um OK_, caso contrrio ser um
INVALID_HANDLE_VALUE.
Um parmetro uma string. Como voc deve ter notado, foi criada uma constante que em tempo de compilao deixa de
existir e substituda a referncia da constante pelo seu valor. Sempre recorra ao uso de constantes para evitar erros de
programao difceis de detectar.
Use sempre como prefixo o nome do objeto que precisa do parmetro (no exemplo acima FORBAX) usando um underscore
(_) onde ficaria o espao e em seguida descrevendo a finalidade do parmetro separada por underscore onde houver
necessidade de espao. Tudo em maisculo.
Nomeie a constante que armazenar o valor de modo idntico ao valor e lembre-se que voc no pode ter dois parmetros
iguais no SPG. Ento a string deve ser nica. Voc pode descobrir se houve uma tentativa de criar um parmetro que j
existe por verificar se o retorno de InserirParametro INVALID_HANDLE_VALUE.
Lembre. O valor string de um parmetro deve atender as seguintes expectativas:

Estar armazenado em uma constante de compilao e ser referido por essa constante sempre.

A string deve ser maiscula e deve-se usar underscore (_) no lugar de espao.

Deve-se colocar o nome do mdulo que tornou o parmetro necessrio seguido por underscore.

A constante deve ser nomeada segundo o seu valor.

O valor deve ser nico em todo o sistema.

Nota: Explicaes mais detalhadas e especficas podem ser encontradas nos comentrios do arquivo classes.pkg.

2011 Atual Sistemas. Todos os direitos Reservados.


Ao fazer uso desse material voc est automaticamente concordando com o termo de licena na pgina 3.

Fascculos do Desenvolvedor

SRG Quando Necessrio 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 informao que no tem um valor fixo determinado. Por exemplo, o dilogo Acrescimo (Acrescimo.dg) no
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 aps ser fechado. Para resolver esse problema, basta se recorrer ao Sistema de Registros
Globais.
Um registro constitudo de identificador e um valor. Um identificador, ou chave, deve seguir as seguintes regras:
Estar armazenado em uma constante de compilao e ser referido por essa constante sempre.
A string deve ser maiscula e deve usar underscore (_) no lugar de espao.
Deve-se colocar o nome do mdulo que tornou o parmetro necessrio seguido por underscore (FORBAX_).
A

constante

deve

ser

nomeada

segundo

seu

valor,

porm

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 excees.
No caso do problema acima, segue abaixo o modelo de como se resolveria a questo da atribuio e retorno do valor
usando-se um registro.
// ESTMOV.VW cabealho
Use vdfclasses.pkg
Use Acrecimo.dg
// Dentro
//
Procedure
Integer
Number

do EstMov...
OnClick
iResult
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.
End
End
End_Procedure

A seguir note o que ser necessrio fazer no arquivo Acrecimo.dg.


// ACRESCIMO.DG cabealho
Use vdfclasses.pkg
Define REG_ESTMOV_ACRESCIMO for |CS"ESTMOV_ACRESCIMO"
// Dentro
//
Procedure
Integer
Number

de Acrescimo...
Activating Returns Integer
iResult
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
End_Procedure
Procedure Deactivating Returns Integer
Integer iResult
Number nVrAcrecimo

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex

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
End_Procedure

Os exemplos acima mostram como usar o sistema de registros. claro que como voc o usar no se limitar somente a um
modelo como esse.
Para o uso de registro voc lidar com as funes CriarRegistro, AlterarRegistro, LerRegistro e RemoverRegistro. Todas
essas funes quando funcionam com xito retornam OK_ e quando falham retornam INVALID_HANDLE_VALUE. Sempre
verifique esse valor de retorno, pois caso qualquer uma das funes falhem, nenhum efeito ocorrer no sistema de registros.
Por exemplo, suponhamos que por descuido voc crie uma chave e no a remova em determinada situao. Ao tentar cri-la
novamente, se identificar que uma chave j existe e a funo CriarRegistro ir falhar. O que significa que o valor que voc
passou no ser armazenado porque uma chave idntica foi encontrada. Caso voc no 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 lgica.
Nota: Explicaes mais detalhadas e especficas podem ser encontradas nos comentrios do arquivo classes.pkg.

GDM Quando Necessrio Passar Dados Mltiplos


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
continer.
Para entender em que situaes deve se usar um continer tenha sempre em mente os seguintes passos. Se os pontos
delineados abaixo forem atendidos, ento voc deve usar um continer para a sua tarefa.
No possvel ou no benfico transmitir a informao com um ou mais parmetros.
No possvel ou no benfico transmitir a informao com um ou mais registros.
O uso de continer tornar o fonte mais fcil de entender.
A quantidade de dados em questo varia conforme as circunstncias 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, ento talvez seja apropriado usar um continer.
A definio de continer e o uso so bem simples. Um continer um Array com um identificador nico, similar ao utilizado
pelo sistema de registros globais. O identificador deve ser passado para se usar o continer. Esse identificador uma string e
a seguinte conveno deve ser usada para se nomear um identificador.
Estar armazenado em uma constante de compilao e ser referido sempre por essa constante.
A string deve ser em maisculo e deve usar underscore (_) no lugar do espao.
Deve-se colocar o nome do mdulo que tornou o parmetro necessrio seguido por underscore (FORBAX_).
A

constante

deve

ser

nomeada

segundo

seu

valor,

porm

usando

um

prefixo

CON_

(Ex.

CON_FORBAX_MEU_REGISTRO).

O identificador deve ser nico em todo o sistema.

Por exemplo, o procedimento mGravaLogOperacao que responsvel por exibir o dilogo LogOperacao costumava fornecer
dados para a grid que havia no dilogo. Esses dados eram fornecidos diretamente se usando um handle para ter acesso a
grid. Assim eram acrescidas informaes ao contedo 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 licena na pgina 3.

Fascculos 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))
//...
End
//...
End
//...
End_Procedure

Esse modelo funciona com componentes que no so iniciados atrasados (em modo deferred). Uma vez que o LogOperacao
passou a ter a inicializao atrasado, se tornou necessrio um mtodo para o transporte dessas informaes que eram
reunidas antes da abertura do dilogo.
Como voc pode notar tambm, alm ser necessrio preencher a grid, tambm era necessrio informar o valor do Label de
um TextBox e o Visible_State de outro. Porm esse dois problemas podem ser facilmente resolvidos com um registro e um
parmetro para cada um respectivamente.
No caso da grid apenas um continer de dados resolveria o problema, e isso ilustrado na soluo 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

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


//...
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))
//...
End
//...
End
Get RemoverConteiner of (oRecursosGlobais(Self)) CON_LOGOPERACAO_GRADE to iResult
//...
End_Procedure

A funo CriarConteiner cria um continer com o identificador nico que foi passado para ela. Caso nenhum continer com
o

mesmo

identificador

tenha

sido

criado

tudo

corra

bem,

retornado

OK_;

caso

contrrio

retorna

INVALID_HANDLE_VALUE.
Um continer simplesmente um objeto cSetTabela, uma classe derivada da classe Set (um implemento de Array). A
funo Conteiner retorna um handle para que voc tenha acesso a esse objeto. Porm, evite o uso dessa funo e sempre
copie o valor retornado a partir dela para um handle, caso voc tenha que recorrer a funo Conteiner constantemente. Isso
porque toda vez que a funo Contener chamada, uma busca realizada para achar o continer segundo o identificador
informado. Caso nenhum continer seja encontrado, INVALID_HANDLE_VALUE retornado.
O mtodo propriedade ValorConteiner usado para se alterar/consultar os elementos do continer informado (usando
Get/Set respectivamente). Caso deseje alterar os elementos do continer por um handle, ter o mesmo efeito que o uso
desse mtodo.
Por fim, o mtodo RemoverConteiner usado para remover o continer do Gerenciador de Dados Mltiplos. Lembre-se
sempre de usar esse mtodo e deixe que o gerenciador se encarregue de destruir o continer com seus elementos. Nunca
envie Destroy para o handle de algum continer, porque a referncia permanecer no gerenciador.
Segue abaixo as alteraes que seriam necessrias no Dilogo 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 licena na pgina 3.

Fascculos do Desenvolvedor
Define LOGOPERACAO_ABORTAR_VISIVEL for |CS"LOGOPERECAO_ABORTAR_VISIVEL"
Cd_Popup_Object LogOperacao is a ModalPanel
//...
//... Faz declarao 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
End
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
End_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
End_Procedure
Cd_End_Object

Conforme demonstrado nessa situao 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 numerao dos campos
da tabela. O procedimento CriarTabelaDinamica responsvel por reservar o slot e reunir os meta-dados referente ao
nome das colunas. A propriedade phTabela contm o manipulador do slot reservado. A funo Campo retorna o nmero
do campo conforme a string passada. Por fim, a funo CampoValorCorrente retorna o valor do campo informado.
Aps ser utilizado, o objeto deve ser destrudo o quanto antes. Durante a destruio, a classe se encarrega de liberar o slot e
fechar a tabela.

Nota

A classe cRecursosGlobais possui uma srie de usos no alistados aqui. Explicaes


mais detalhadas e especficas podem ser encontradas nos comentrios do arquivo
classes.pkg.

Captulo 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 preocupao. Principalmente em nosso caso, o bom gerenciamento de recursos da
base extremamente necessrio j que a base de dados embutida do Visual DataFlex uma base no relacional. Assim, cada
tabela possui um arquivo dedicado que acessado usando recursos comuns do computador, da rede local ou do domnio.
Esse captulo aborda como fazer o bom uso de comandos para abertura de tabelas de maneira que no desperdicemos
recursos reservando tabelas que no final no usaremos.

Bom uso do comando Open


Antes que uma tabela (ou arquivo de dados) possa ser referenciada no cdigo, junto com os respectivos campos, para que
ento seus dados sejam lidos ou alterados, necessrio 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 execuo do programa ele
reserva a tabela para uso.
O comando open deve ser usado com critrio e as tabelas no devem ser abertas at que elas tenham realmente de ser
utilizadas. Por isso, devem ser removidos os comandos open que esto no escopo global dos arquivos.
Atualmente muitos cabealhos esto em uma situao 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_End_Object

Isso faz com que, nesse exemplo, os arquivos CAXPRE e FCAXPRE sejam abertos durante a criao do objeto Client_Area. O
que derruba a desempenho do sistema desde a inicializao quando no 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_End_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

Fascculos do Desenvolvedor

Sempre que possvel, use Declare_DataFile


Em algumas situaes, no possvel compilar a aplicao porque fora feita referncia a alguma tabela que ainda no fora
aberta. Para solucionar esse problema, o programador geralmente recorre ao comando Open. Embora essa tenha sido a
soluo para o problema em verses antigas do VDF, as verses mais recentes do Visual DataFlex dispes 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 compilao que o comando Open, com a nica diferena
que ele no reservar a tabela para uso em tempo de execuo. Isso se torna extremamente til em aplicaes que fazem
extenso uso de DDOs, j que os dicionrios de dados se responsabilizaro em abrir a tabela no momento certo.
Assim, em pacotes (.PKG) que precisamos usar tabelas do banco para prover funcionalidades para Janelas que possuem
DDOs, mas no se possvel compilar esses pacotes por falta do comando Open, basta usar o comando Declare_DataFile
neste pacotes. Veja um exemplo caso no cdigo abaixo.
// FUNCOES.PKG
Open CADPRO
Open ESTSAL
Function fValida_Desconto Global Date dData Returns Number
If (CADPRO.DESCONTO_OK = "S") Begin
// Fonte continua...
End
End_Function

Nesse exemplo, o comando Open precisa estar presente no fonte para que seja possvel compilar a linha que faz referncia
ao CADPRO.DESCONTO_OK. Porm o fato de o comando Open estar no escopo global desse PKG faz com que esse
comando open seja executado durante a inicializao em algum ponto onde esse arquivo incluso no projeto. Se ns
estamos usando o Open apenas para garantir a compilao, 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...
End
End_Function

Nesse exemplo, a tabela no ser aberta quando o PKG for incluso no projeto durante a inicializao do programa e ns
conseguiremos compilar esse arquivo sem nenhum problema com a referncia ao campo CADPRO.DESCONTO_OK.
Contudo, nesse caso, quando fValida_Desconto fosse chamada, alguma outra parte da aplicao deveria se responsabilizar
em j ter essas tabelas abertas. Se no possvel garantir que a funo fValida_Desconto ser chamada apenas com CADPRO
e ESTSAL abertos, ento 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...
End
End_Function

Nesse ultimo caso, o open abrir a tabela e, por ele no estar no escopo global, isso s ocorrer quando a funo
fValida_Desconto for chamada. Essa deve ser a ultima alternativa para abrir a tabela. Geralmente, funes que acessam dados
de tabelas so chamadas a partir de Janelas que j abriram essas tabelas, o que torna o uso de Declare_DataFile mais
desejvel para um fonte mais compreensvel e seguro. Isso, porque se voc usar o Open dentro da funo, voc ter de uslo em cada funo que precise fazer uso do arquivo em questo (no nosso exemplo, o ESTSAL).
Resumindo: Use o comando Open somente quando Declare_DataFile no puder realmente resolver a situao.

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


Os arquivos DDs j esto fazendo uso desse tipo de recurso, por declararem em tempo de compilao 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...
End_Procedure
// Fonte continua...
End_Class

Uma classe de Dicionrio 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 no for usada
pelo usurio durante a execuo. Dessa forma, nenhum recurso do sistema usado a menos que seja de fato necessrio.

2011 Atual Sistemas. Todos os direitos Reservados.


Ao fazer uso desse material voc est automaticamente concordando com o termo de licena na pgina 3.

11

Captulo 3

Usando Comando Open As, Slots


e Apoio dos Recursos Globais
A base de dados do Visual DataFlex utiliza um mtodo para organizar suas tabelas, ou arquivos de dados, de modo que cada
uma delas receba um nmero em uma lista que chamado de FileList. Assim cada tabela no sistema possui um nmero, e
cada nmero desse tecnicamente chamado de slot.
Esse captulo abordar algumas tcnicas providas pelo Visual DataFlex e por bibliotecas desenvolvidas pela Atual Sistemas
para fazermos bom uso desses slots para determinados tipos de consultas.

Abrindo Uma Cpia de Um Arquivo de Dados


Em alguns casos ns precisamos realizar uma consulta em uma tabela, mas isso no possvel porque ns temos dados no
buffer daquela tabela que no podem ser afetados. Ou ento, pode acontecer de precisamos de comparar dois registros da
mesma tabela. Como podemos alcanar um registro especfico de uma tabela sem afetar o registro corrente do buffer?
O comando Open As serve justamente para esse propsito. Com esse comando, ns podemos abrir uma cpia 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 operaes comuns de consulta podem ser realizadas usando-se comandos de acesso a dados de um arquivo de dados
que usam nmeros como referncias ao invs do nome simblico dos campos (ex. Set_Field_Value, Get_Field_Value,
VFind). Ao final da tarefa, depois de termos realizado a consulta, ns nunca deixamos de chamar o comando Close para
liberar a cpia.
Embora essa tcnica no seja nova h alguns reajuste cuja implementao necessria. Isso porque preciso uma
segurana 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 cpia, isso resultar em problemas que inicialmente podem passar despercebidos,
mas que so completamente comprometedores.
Ateno: No use reread ou operaes de DDO que fazem alteraes em arquivos de dados quando houver alguma cpia de
um arquivo de dados aberta.
Por exemplo, era comum o uso da funo fNewFile ou um nmero especfico (geralmente 1500) para determinar o slot que
a cpia do arquivo seria aberta. Esses mtodos no so seguros e devem ser corrigidos. Segue abaixo uma situao tpica.
// CADIMP.RV Contedo
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
Get_FieldNumber
Get_FieldNumber
Get_FieldNumber

CADIMP.ID
CADIMP.CAMINHO
CADIMP.DESCRICAO
CADIMP.ESTACAO

to
to
to
to

iCampoID
iCampoCaminho
iCampoDescricao
iCampoEstacao

Move (fNewFile()) to iFile // Funo insegura para chamadas concorrentes...


Open "CADIMP" as iFile
Clear iFile
Set_Field_Value iFile iCampoID to iID
Set_Field_Value iFile iCampoCaminho to sCaminho

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


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
End
Close iFile
Function_Return sEstacao
// Fonte continua...

Como proceder em um caso como esse? Nos casos onde necessrio o uso de "Open as" dever se optar entre dois
mtodos de uso. O primeiro a reserva de Slots atravs 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 funes de oRecursosGlobais est o gerenciamento dos slots vagos do FileList que esto sendo usados em
tempo de execuo pela aplicao. Esse gerenciamento centralizado impede que haja conflitos no uso dos slots livres.
Seguindo a necessidade do exemplo dado anteriormente, mostraremos a soluo por meio do gerenciador de slots de
oRecursosGlobais.
// CADIMP.RV Contedo
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
Get_FieldNumber
Get_FieldNumber
Get_FieldNumber

CADIMP.ID
CADIMP.CAMINHO
CADIMP.DESCRICAO
CADIMP.ESTACAO

to
to
to
to

iCampoID
iCampoCaminho
iCampoDescricao
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
End
Close hArquivo
Send LiberarSlot of (oRecursosGlobais(Self)) hArquivo
Function_Return sEstacao
// Fonte continua...

Como voc pode notar a funo ReservaSlotLivre de oRecursosGlobais tem como retorno um handle para um slot livre
que a aplicao pode utilizar. Esse handle deve ser utilizado como manipulador da cpia 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 licena na pgina 3.

13

14

Fascculos do Desenvolvedor
no final da tarefa. Para liberar esse manipulador no gerenciador ns usamos LiberarSlot de oRecursosGlobais. S chame
LiberarSlot aps 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 segurana, mas
no simplificam o processo em si. Para que houvesse uma simplificao 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 nmero de variveis e
complicaes que se reduz no uso dele.
// CADIMP.RV Contedo
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
End
Send Destroy to hcstdCadImp
Function_Return sEstacao
// Fonte continua...

Conforme demonstrado nessa situao 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 numerao dos campos
da tabela. O procedimento CriarTabelaDinamica responsvel por reservar o slot e reunir os meta-dados referente ao
nome das colunas. A propriedade phTabela contm o manipulador do slot reservado. A funo Campo retorna o nmero
do campo conforme a string passada. Por fim, a funo CampoValorCorrente retorna o valor do campo informado.
Aps ser utilizado, o objeto deve ser destrudo o quanto antes. Durante a destruio, a classe se encarrega de liberar o slot e
fechar a tabela.
Ateno: No chame o comando Close para fechar um slot aberto por cSlotTabelaDinamica jamais.

Nota

A classe cSlotTabelaDinamica possui uma srie de usos no alistados aqui.


Explicaes mais detalhadas e especficas podem ser encontradas nos comentrios do
arquivo classes.pkg.

Apndice I

Recomendaes Para um Bom Fonte


Segue abaixo sete recomendaes que se forem seguidas com afinco combinadas com criatividade o faro no somente um
programador, mas sim um Desenvolvedor.
1.

No escreva longos procedimentos. Um procedimento no deve ter mais de dez ou doze linhas, deve ser escrito
para ser reutilizvel para mais de uma situao e deve evitar afetar valores globais.

2.

Todo procedimento deve ter uma finalidade clara. A finalidade de um procedimento no pode ser mesclada com a
finalidade dos procedimentos que vem antes ou depois dele. Um bom programa uma srie de procedimentos
limpos que no se sobrepe um ao outro.

3.

No use caractersticas muito complexas da linguagem. Se o seu trabalho no feito com simples declaraes de
variveis, chamadas de procedimentos, classes, declaraes de controle de fluxo e operadores aritmticos, alguma
coisa est errada. Quando voc usa os recursos bsicos da linguagem isso o faz pensar no que voc est
escrevendo. No complique o que pode ser simples.

4.

Nunca use recursos da linguagem que voc no tem certeza como se comportaro. Se voc costuma escrever
cdigo que voc no tem certeza como se comporta, melhor reavaliar em que rea voc quer trabalhar.

5.

Evite ao mximo usar Copiar & Colar, principalmente se voc um principiante. Assim voc usar o menor nmero
de arquivos possveis.

6.

Evite usar referncias a valores abstratos cuja origem pode ser desconhecida e o valor incerto (buffer, variveis
globais).

7.

De tempos em tempos tente entender como as bibliotecas que voc usa funcionam. Procure ver porque
determinados processos so de um modo especfico.

Em suma, essas recomendaes podem parecer genricas, mas tente v-las de um modo prtico ao cumprir com seu dever.

Siga um padro claro


H muitos erros escandalosos em Visual DataFlex que podem ser encontrados em fontes de Desenvolvedores conceituados,
mas isso no significa que o erro deles deve ser o nosso. Vamos considerar alguns erros bsicos de programao que devem
ser evitados.
O Desenvolvedor deve sempre levar em mente ao escrever cada linha de cdigo.

Essa linha deve ser clara e inteligvel.

O fonte final deve estar asseado aparentando ordem e esmero, devidamente posicionados para melhor
compreenso.

Ser que essa linha realmente necessria?

Existe alguma forma de simplificar o que eu estou escrevendo agora?

Nunca poupe linhas que significaro cem linhas a menos no futuro e eliminaro possveis bugs, mas nunca escreva mais
linhas de cdigo 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 recomendaes tericas, segue abaixo algumas recomendaes prticas em VDF.
Sempre use notao matemticas em declaraes de controle de fluxo e condicionais ao invs de expresses verbosas
antigas do VDF. Apenas em timo caso use essas expresses verbosas (ex, constraint), j que elas dificultam a compreenso
do fonte.

16

Fascculos do Desenvolvedor verso 1.6.1


Assim, evite sempre que possvel o uso de EQ, GE, GT, LE, LT e NE. Ao invs disso use sempre que possvel <, <=, =, not,
<>, >= e >. (Ao usar esses operadores voc ser obrigado a usar parnteses, o que torna o fonte ainda mais claro.)
Verifique sempre se no possvel resumir a uma linha uma condio if ... else de duas linhas. Em muitos casos isso
plenamente possvel com a chamada expresso ternria. 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 no possua um operado ternrio nativo, possvel criar uma expresso ternria usando a funo If.
Move (If((CADPRO.DESCONTO_OK = "S"), iDesconto, iValor)) to ESTMOV.DESCONTO

Como voc pode ver, a expresso abaixo compacta e bem clara para entender, poupando uma linha para a viso de um
programador que procura entender o fonte.
Outro caso quando estamos decidindo se atribumos verdadeiro ou falso a algum elemento. Nesses casos, no h
necessidade de se usar IF ... Else. Por exemplo, note o cdigo 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 desnecessrio usarmos duas linhas. Ns poderiamos declarar isso simplesmente assim.
Set Visible_State of oDesconto to (CADPRO.DESCONTO_OK = "S")

Evite operadores desnecessrios. Como ns sabemos, o VDF uma linguagem em si verbosa que possui certos operadores
como os parnteses, Begin e End que so desnecessrios em certas circunstncias. A menos que eles realmente contribuam
para um melhor entendimento do fonte, evite-os. Veja um caso de uso desnecessrio abaixo.
If (CADPRO.DESCONTO_OK = "S") Begin
Move iDesconto to ESTMOV.DESCONTO
End

O cdigo abaixo deveria ser simplesmente assim:


If (CADPRO.DESCONTO_OK = "S") Move iDesconto to ESTMOV.DESCONTO

Tenha uma linha de raciocnio clara sobre o seu propsito. Em alguns casos, programadores simplesmente complicam
demasiadamente o cdigo com linhas em excesso onde algumas nem sero executadas. Obviamente, para evitarmos que
isso acontea, precisamos primeiro escrever essas linhas por ns mesmo, nunca copiar e colar. Depois de escrever, tente ver
se no tem como dizer a sua lgica de um modo mais direto. Veja o exemplo abaixo.
Integer iRet
// No Final da Funo ...
Get YesNoCancelBox "Tem certeza mesmo?" "Ateno" 1 To iRet
If (iRet = MBRYes) Begin
// Faz alguma coisa ...
Function_Return True
End
Else if (iRet = MBRNo) Function_Return False
Else if (iRet = MBRCancel) Function_Return False
Function_Return

Nesse exemplo, h trs erros presentes no fonte. Primeiro, o programador usou um YesNoCancelBox para uma situao em
que um YesNoBox seria o suficiente, j que ele trata o resultado do Cancelar da mesma forma que ele trata o No. Segundo,
todos esses condicionais poderiam ser resumidos em uma nica linha. Terceiro, no necessrio um Else para chamar um
Function_Return ou um Procedure_Return quando a sentena condicional a ultima sentena do mtodo em questo.
Corrigindo esse cdigo, o formato mais simples e direto seria o seguinte.

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex

// No Final da Funo ...


If ((YesNoCancelBox("Tem certeza mesmo?", "Ateno"))
// Faz alguma coisa ...
Function_Return True
End
Function_Return False
Function_Return

= MBRYes) Begin

No crie validaes em campos de entrada de dados que impea os usurios de sair deles at digitar o dado correto.
Em tais procedimentos de validaes ao sair do campo, caso seja retornado o valor 1, o usurio impedido de sair do
campo. Isso um erro de layout crasso. No cometa esse erro.
Caso voc precise validar um dado quando o usurio sair de um campo, faa de um modo que no afete o fluxo de uso da
aplicao. Por exemplo, limpe o valor invlido do campo, altere algum label que sirva como status, coloque a cor de fundo
do campo para vermelho, porm nunca exiba uma caixa de dilogo como resposta e muito menos impea o usurio 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 explicao ser fornecida
aqui.
Todo arquivo de dados em VDF pode ser acessado por um canal chamado de buffer do arquivo. Quando ns acessamos os
dados de uma tabela usando apenas o nome da tabela e o nome da coluna (ex,Stop_Box CADPRO.MATRICULA), ns
estamos na realidade lendo o buffer desse arquivo de dados diretamente. Nas primeiras verses do VDF, essa tcnica era
satisfatria, entretanto quando necessrio ler e alterar vrios registros da mesma tabela em vrias telas simultaneamente, o
uso de um buffer que s pode direcionar um registro por vez para vrias tarefas simultneas pode ser desafiador. Isso
porque o buffer s direciona um registro por vez e ele um s para toda a aplicao.
A fim de suprir essa deficincia, foi provido o DD ou Dicionrio de Dados, que nada mais do que uma classe de objetos
que usam o buffer para armazenar os dados de um registro especfico. Assim, com o uso de objetos DD ou DDOs ns
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 funes do DDO para ler os dados da tabela, eu vou ter os valores do registro 20. Com tal forma de organizao
eu posso ter vrios DDOs apontando para vrios 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
usurio altera esses valores, o DDO mantm um registro das alteraes. 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 gravao de dados via buffer.
Os problemas relacionados ao uso de buffer e DDOs comeam a partir do momento que alguns programadores no
entendem esse fato, e tambm no compreendem que embora o buffer no afete a posio de um DDO, o DDO afeta a
posio de um buffer porque, no final das contas, o DDO usa o buffer para ler, criar, alterar e deletar registros. A seguinte
ilustrao mostra quatro DDOs apontando para quatro registros diferentes da tabela X e a relao que eles tm 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 licena na pgina 3.

17

18

Fascculos do Desenvolvedor verso 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 inteno seja buscar valores que esto na tabela sem afetar os valores que esto no DDO. Tambm,
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 invs disso, use recursos do prprio DDO para esse
fim (ex Get_Field_Current_Value, Set_Field_Changed_Value, etc).
Por exemplo, nunca faa como no seguinte cdigo.
Object CadPro_DD is a CadPro_DataDictionary
End_Object
Object CadPro_Desconto is a dbForm
Entry_Item CADPRO.DESCONTO
End_Object
Procedure AtualizarDesconto Number nDesconto
If (Value(CadPro_Desconto(Self)) = 0) Set Value of (CadPro_Desconto(Self)) to nDesconto
End_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 informao. Isso diminui a perspectiva de segurana da aplicao, j que podem ser inseridos
processo inesperado nesse caminho.
Seria tambm um grande engano usarmos algo semelhante ao exemplo seguinte.
Procedure AtualizarDesconto Number nDesconto
Move (CADPRO.VALOR nDesconto) to nDesconto
// fonte continua ...
End_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 no estar refletindo o valor correto devido alguma atualizao no valor que ainda no foi
salva no buffer. Este um erro mais grosseiro ao cdigo que pode significar bugs srios j que nem sempre algum problema
prontamente observado.
O prximo exemplo demonstra qual o acesso correto aos dados de um registro mantido em DDO.
Object CadPro_DD is a CadPro_DataDictionary
End_Object
Object CadPro_Desconto is a dbForm
Entry_Item CADPRO.DESCONTO
End_Object
Procedure AtualizarDesconto Number nDesconto

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


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
End_Procedure

Como voc pode ver, o acesso e a alterao so feitos diretamente no DDO. No 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 afirmao enganosa. Mais
informao ser preparada sobre esse tema, mas procure entender corretamente essas prticas seguras para que voc possa
manipular tanto buffer quantos DDOs como uma ferramenta ao seu favor, no um pesadelo.

Desfrute Do Seu Trabalho


Esforce-se em seguir essas sugestes. Qualquer esforo nesse respeito beneficiar primariamente voc como desenvolvedor.
Lembre-se que seu trabalho ser verificado e visto por outros vrias vezes. O legado que voc deixa em uma base de cdigo
pode ser duradouro. Esforce-se em ser lembrado como algum inteligente, prtico e organizado. Isso lhe poupar dores de
cabea em ter que corrigir seu prprio cdigo outras vezes, ou lhe poupar ainda a vergonha de no consegui explicar para
outro Desenvolvedor como o seu prprio cdigo 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 licena na pgina 3.

19

Apndice II

Ativao e Desativao de Janelas


O Mtodo Sugerido
O mecanismo de Ativao e Desativao tem um longo histrico. Ele foi construdo como parte da original Interface de
usurio orientada a objetos e foi submetido a muitas mudanas. Teve de ser estendido para suporta objetos modal e
modeless. Aps isso foi expandido para trabalha com objetos orientados por dados (DEOs). Mais tarde, ele foi alterado para
suportar controles do Windows. No surpreende que o resultado final seja uma variedade de formas de fazer as coisas
funcionarem e mais outros muitos modos de fazer as coisas no funcionarem. Mais cedo ou mais tarde, todo mundo acaba
esbarrando em alguma questo sobre ativar e desativar dilogos.
O propsito desse artigo e prover uma srie de orientaes para o processo de ativao e desativao. 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 tambm ver quais voc deve deixar sozinhas e isso pode te surpreender. No sero abordados todos
os mtodos de ativao e desativao e talvez voc conhea outro procedimento. Porm, ser explicado bastante a respeito
do processo a fim que voc possa trabalhar mais eficientemente independente do mtodo que voc escolha.
Vamos dar a definio de alguns termos.
Um dilogo um dilogo do Windows. Uma view um dilogo modeless como um dbView ou um View. Um dilogo modal
um dilogo modal como um dbModalPanel ou um ModalPanel. A classe determina se o dilogo modal ou modeless.
Voc no pode transformar uma view em modal e voc no pode transformar um dilogo modal para modeless.
Um objeto DEO um objeto orientado a dados que trabalha com base na estrutura de Dicionrio de Dados / Objeto de
Entrada de Dados (DD/DEO). Um objeto DEO pode ser um container ou um controle. Exemplos de containers DEO so
dbView, dbModalPanel e dbContainer3D. Exemples de controles DEO so dbForm e cdbTextEdit.
Um objeto non-DEO um objeto que no compreende a estrutura DD/DEO. Exemplos de containers non-DEO so View,
ModalPanel e Container3D. Exemplos de controles non-DEO so Button, Form e cTextEdit.
Um dilogo DEO um dilogo que compreende a estrutura DD/DEO. Um dilogo DEO pode conter uma mistura de objetos
DEO e non-DEO. Um dilogo non-DEO pode conter apenas objetos non-DEO.
Ativao se refere um dilogo que no est que ainda no foi desenhado. Um dilogo est inativo quando no est sendo
exibido e ativo quando passa a ser exibido.
O objeto Foco o objeto que possui o foco de entrada.
Mudana de Foco se refere a troca de foco entre objetos ativos. Isso pode ocorrer dentro de um dilogo ou atravs de
dilogo. Freqentemente o termo ativar usado para referir-se a ativao ou a mudana de foco. Nesse artigo, ativar referese somente a ativao.
Desativao significa fechar o dilogo e torn-lo inativo.

Ativao
Do ponto de vista do usurio a ativao torna o dilogo visvel e disponvel para uso. De uma perspectiva tcnica, a ativao
cria e exibe o objeto dilogo do Windows e todos os objetos filhos dentro do dilogo, 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

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


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 ativao um pouco diferente entre views e dilogos modais. Enquanto muito do comportamento similar
h algumas diferenas srias. Comearemos com as views.

Ativao de Views
A ativao da view pode ser representada com esse pseudocdigo. Esse cdigo assume que a que a view ainda no est
ativa (essa uma ativao e no uma mudana 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
ativao. 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. Ento, 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 mudana de foco).
Do ponto de vista de customizaes de view, ns s estamos interessados em duas mensagens: Activate e Activating.

A Mensagem Activate
Voc nunca precisar enviar a mensagem Activate a fim de realizar a ativao. Porm, essa uma mensagem muito til para
complementos.
Se voc deseja cancelar a ativao, complemente e no encaminhe (forward) a mensagem.
Se voc deseja faze alguma mudana no dilogo antes da ativao, voc pode faz-la antes de encaminhar a mensagem por
que na verdade o processo no foi iniciado ainda.
Lembre-se que o mtodo Activate usado para ativao e mudana de foco. Se voc desejar que suas alteraes 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 ativao
IF (not(bActivate)) Begin
// chama um mtodo local para determinar se a ativao permitida.
Get CanActivate to bCanActivate
IF (not(bCanActivate)) Begin
Procedure_Return 1
End
// Chama um mtodo local para efetuar outras operaes locais antes
// de comear
Send PreActivateDialog
Forward Get Msg_Activate to iRet
End
Else Begin // Se for usado para mudana de foco
Forward Get Msg_Activate to iRet
End
Procedure_Return iRet
End_Procedure
2011 Atual Sistemas. Todos os direitos Reservados.
Ao fazer uso desse material voc est automaticamente concordando com o termo de licena na pgina 3.

21

22

Fascculos do Desenvolvedor verso 1.6.1

A funo CanActivate e PreActivateDialog so exemplos e no existem voc teria de cri-las.


Agora ns 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 ativao interrompida a partir desse ponto, isso considerado
um erro de programao e as coisas no vo ficar boas.
Voc pode complementar aps ter encaminhado a mensagem Activate, mas voc s poder fazer isso com views e no com
dilogos 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
dilogo. Note que embora voc nunca deva enviar Activate para realizar ativao, voc pode envi-lo para mudana de foco.

O Evento Activating
Activating chamado por cada objeto no dilogo em uma ordem do topo para baixo. Ele chamado antes que o objeto do
Windows seja criado. Tambm 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 alteraes mais agressivas aos objetos filhos. Voc no deve tentar fazer qualquer coisa que mude o foco,
desative objetos ou altera a arvore de foco existente. Voc no pode usar essa mensagem para cancelar a ativao ela no
foi criada para isso. Portanto, no retorno um valor de dentro desse evento.

Ativao de Dilogo Modal


A ativao do dilogo modal quase a mesma que a da view, mas h algumas diferenas chaves. Voc ativa um dilogo
modal por enviar a mensagem Popup. Ela faz o seguinte.
Popup
Activate
Create_Dialog (Dilogo do Windows criado!)
---Um novo nvel da interface do usurio 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 diferena aqui que Create_Dialog chamada entre Activate e Add_Focus. Isso fora o comportamento modal
por desabilitar os objetos origens e iniciar um novo nvel de IU. Iniciar um novo nvel de IU significa que o procedimento
Create_Dialog no est completo at que o dilogo modal esteja fechado. Isso muda completamente o comportamento em
relao ao complemento posterior na mensagem Activate. O que foi posto posteriormente no executado at que o
dilogo feche. Sendo assim, no use complementos posteriores na mensagem Activate. Entretanto, voc ainda pode usa
Activate para os mesmo pr-complementos usados na ativao de uma view.
H outra diferena tcnica. Por razes internas, o controle Windows do dilogo 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 no
precisa criar esse controle. Normalmente isso no muda nada, mas se voc precisar fazer alguma coisa com o controle
dilogo exterior antes de ele ser criado, voc deve fazer isso no Activate. Somente o controle dilogo criado
prematuramente todos os filhos do dilogo modal so criados segundo o modelo normal.
Talvez voc notou que ns no usamos Popup_Modal para ativao. Essa mensagem funciona mas no necessria.
Popup_Modal uma mensagem herdada que chama Popup.

Mudana de Foco
Voc nunca deve precisar usar Activate para ativar um dilogo. Voc pode enviar Activate para mudar o foco. Isso feito
com freqncia dentro de uma view ou de um dilogo modal quando se muda o foco de um objeto para outro. Ao mudar o
foco entre views, recomendvel que voc trate isso como uma mudana de view. Primeiro ative a view e, se necessrio,

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex


envie Activate para um objeto dentro da view. Lembre-se que a mudana de foco ocorre quando o Activate_State da view
est apontado para true.

Desativao
Desativao o processo de fechar um dilogo ativo. Da perspectiva do usurio a view est fechada quando ela no est
mais visvel e utilizvel. Internamente, o dilogo e todos os seus filhos so removidos da rvore de foco do DataFlex, todos
os objetos do Windows no dilogo so destrudos e o foco movido para alguma outra parte da aplicao.
Diferente do processo de ativao onde views e dilogos modais se comportam de maneiras diferentes uns dos outros, o
processo de desativao para esses dois tipos de dilogo so iguais. Contudo, h algumas diferenas significantes entre os
dilogos DEO (dbView, dbModalPanel) e os non-DEO (View, ModalPanel).

Desativao e Dilogos DEO


Comearemos com os dilogos DEO porque esses so usados mais freqentemente.
Close_Panel
Exit_Function
Request_Cancel
Verify_Exit
Executa a mensagem Verify_Exit. Se retornar zero, continua.
Deactivate
Send Activate para outro dilogo (mudana 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 (Destri os controles do Windows)

Como voc pode ver, esse processo um pouco complicado e na verdade ele bem mais complicado. Portanto, ns
comearemos com a parte simples. Eis o que voc precisa saber para controlar a desativao.
1.

Envie Close_Panel para fechar um dilogo. Voc pode envi-lo para o dilogo ou qualquer controle dentro dele.

2.

Crie a sua prpria funo pode-fechar que retorna diferente de zero para cancelar a desativao. Coloque o id de
sua mensagem na propriedade Verify_Exit_Msg do objeto dilogo.

3.

Use o evento Deactivating para controlar qualquer lgica est fechando. Deactivating enviado para cada objeto
no dilogo.

4.

No complemente ou envie qualquer uma das outras mensagens.

Se voc seguir esses passos, voc no ter de se preocupar com as complicaes que sero descritas. A principal
complicao que os objetos DEO tenta fazer coisas demais. Voc talvez ache que todas essas mensagens (Close_Panel,
Exit_Function, Request_Cancel, etc) so todas definidas e manipuladas pelo objeto dilogo via delegao. Com objetos DEO
filhos no assim. Cada classe DEO entende e manipula essas mensagens diretamente. Para piorar as coisas, esses objetos
podem enviar diferentes mensagens para fechar o dilogo (Close_Panel, Exit_Function ou Request_Cancel). Para criar mais
uma complicao, objetos non-DEO (como botes) no entendem essas mensagens e, portanto as delegam. Isso torna difcil
saber qual mensagem deve ser complementada. Dependendo de onde o foco est mensagens para fechar deferentes
estaro sendo enviadas para diferentes objetos. A boa noticia que se voc no complementar nenhuma dessas mensagens,
tudo isso ir funcionar. Enquanto voc usar sua funo pode-fechar no Verify_Exit_Msg do dilogo, 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 dilogo externo, todos os objetos o encontraro e usaro a mesma
funo pode-fechar.
Como exemplo, adicionar o seguinte cdigo a uma dbView ou a um dbModalPanel apenas lhe permitiria fechar o dilogo
quando a data corrente tivesse com o segundo impar (uma tcnica 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 licena na pgina 3.

23

24

Fascculos do Desenvolvedor verso 1.6.1


Set Border_Style to Border_Thick
Function CancelClose Returns Boolean
DateTime dDT
Integer iSec
Boolean bStopIt
// teste intil que retorna true para parar a desativao
// 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
End_Function
Set Verify_Exit_Msg to (RefFunc(CancelClose))

Desativao e dilogos non-DEO


A desativao de um dilogo no DEO muito mais simples. Uma vez que no permitido aninhar objetos DEO dentro de
containers non-DEO, ns sabemos que nenhum desses objetos so DEOs. Deactivation se parecer com o seguinte.
Close_Panel
Deactivate
Send Activate para outro dilogo (mudana 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 (Destri os controles do Windows)

Assim como em dilogos DEO, voc envia Close_Panel para desativar o objeto. Neste caso, enviar Close_Panel para qualquer
objeto no dilogo resultar que a mensagem seja delegada ao objeto dilogo. Se voc deseja cancelar a desativao,
complemente Close_Panel e no encaminhe a mensagem.
Eis um exemplo de como cancelar a desativao de um dilogo 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 intil que retorna true para parar a deseativaao
// 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
End_Function
Procedure Close_Panel
Booleand bStop
Get CancelClose to bStop
If not bStop Begin
Forward Send Close_Panel
End
End_Procedure

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex

O processo de desativao
Uma vez que a desativao foi iniciada (que a mensagem Deactivate foi enviada) o processo o mesmo para todos os
dilogos. Se a desativao j foi iniciada ela no pode ser interrompida e se for, um erro de programao e a aplicao no
ser estvel.
A mensagem Deactivate funciona de dois modos. Ela usada para encontrar o objeto da rea externa para desativ-lo e
ento ela usada para desativar um objeto. Voc tem de saber como enviar essa mensagem com os parmetros corretos e
voc tem que saber como complement-la da maneira correta. Ento esquea! No a envie nem a complemente.
Quando voc fecha um dilogo voc deseja ter certeza que h algum outro lugar para receber o foco. Com views,
dificilmente isso um problema. Com dilogos modais, o sistema tentar dar o foco ao objeto que tinha o foco quando o
dilogo modal foi chamado. Se por alguma razo esse objeto no puder retomar o foco, isto um erro de programao e o
programa no ser estvel.
Objetos filhos so desativados antes de o objeto origem ser desativado.
O evento Deactivating enviado para cada objeto ativo no dilogo em uma ordem debaixo para cima. Voc no pode usar
esse evento para cancelar a desativao. Quando a desativao 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 esto desativados (removidos da rvore de foco e os controle do Windows destrudos). O mtodo
Page_Delete na verdade destri os controles do Windows.
Se voc complementar o cdigo de Deactivating, ser mais provvel que voc faa isso somente no objeto dilogo.

Trabalhando com Dilogo Modal


Dilogos modais so modais por uma razo. Voc deseja cham-los em um momento em particular, e suspender o resto da
aplicao at que o processo deste dilogo modal o fornea uma informao que voc precisa para continuar. Enquanto
voc poderia usar algumas das mensagens que ns abordamos aqui tais como Popup e Deactivating para manipular pr- e
ps-processamento, isso geralmente no a melhor estratgia. Veja o artigo Comunicao entre Views e Dilogos
(http://support.dataaccess.com/Forums/blog.php?b=30, em ingls) para uma discusso cabal deste tpico e um mtodo
sugerido.

Como as coisas do errado


Vrias vezes foi mencionado que coisas ruins acontecem quando a ativao ou a desativao no so corretamente
concludas. H trs coisas que devem ser corretamente sincronizadas para que tudo funcione. Essas so a rvore de foco, os
objetos do Windows e o nvel de IU.
A rvore de foco uma estrutura do DataFlex que controla como a navegao para o objeto seguinte e anterior se dar.
Objetos so adicionados e removidos dessa rvore de foco durante ativao e desativao. Objetos do Windows so objetos
que so controles que so criados durante ativao e destrudos durante a desativao. Quando um objeto adicionado a
arvore de foco, um objeto do Windows deve ser criado e vice-versa. Quando a ativao ou a desativao so derrubadas
impropriamente, voc pode acabar em uma condio onde um objeto est na rvore de foco, mas no existe nenhum
controle do Windows, ou o objeto no 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 nvel da IU s importante com dilogos modais. O nvel da IU o nvel onde o loop de processamento da interface do
usurio DataFlex executado. Normalmente h apenas um nvel que usado por todas as views. Quando um dilogo modal
ativado, o mtodo Create_Dialog cria um novo nvel de IU e suspende o nvel anterior. O nvel de IU permanece suspenso
at que o novo nvel seja finalizado, o que ocorre durante a desativao. Se alguma coisa der errado durante a desativao, o
nvel de IU pode no finalizar. Quando isso acontece o dilogo pode at parecer estar fechado, mas voc estar processando
eventos de IU no nvel de IU errado. Voc pode ver isso com o depurador. Pause o seu programa. Se o dilogo 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 no estejam mais sincronizados.

2011 Atual Sistemas. Todos os direitos Reservados.


Ao fazer uso desse material voc est automaticamente concordando com o termo de licena na pgina 3.

25

26

Fascculos do Desenvolvedor verso 1.6.1


Em todos os casos citados, uma vez que no h sincronia entre Active_State e Window_Handle, no haver um modo fcil de
recuperar a execuo da aplicao. Mesmo que as coisas paream funcionar, nada est funcionando corretamente.
Normalmente voc no precisa se preocupar com nada disso porque o processo de ativao e desativao do DataFlex se
encarrega disso. Se voc est tendo algum problema, voc est fazendo alguma coisa errada. Corrija e tudo ficar perfeito.

Fascculos do Desenvolvedor Orientao Essencial em Prticas e Metodologias em Visual Dataflex

Escreva seu prprio futuro


Todo Desenvolvedor pode escolher entre cumprir tarefas ou ter
paixo pelo que faz, entre fazer o possvel ou fazer o impossvel, entre
escrever um cdigo ou escrever seu prprio futuro.
Atualize suas habilidades como desenvolvedor por conhecer e aplicar
Recursos e Idias providos pelo Desenvolvimento da Atual Sistemas.

Ns Queremos Te Ouvir
Ns apreciaremos qualquer feedback a respeito desse material. Sua opinio e suas sugestes so muito relevantes e pode
nos levar a construir contedos melhores. Sua participao 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 Lcio Bastos

2011 Atual Sistemas. Todos os direitos Reservados.


Ao fazer uso desse material voc est automaticamente concordando com o termo de licena na pgina 3.

27

Anda mungkin juga menyukai