Herança

Delphi

08/12/2008

Vou explicar melhor o problema,tenho um formulario pai e a partir dele criei um form padrao para consulta e um form padrao para cadastro. Quando estou no form consulta funcionarios por exemplo e preciso editar, faço dessa forma:

procedure TfrmConsFuncionarios.btnEditarClick(Sender: TObject);
begin
inherited;//aki nao ta herdando nada ainda nao

inserir := false;//variaveis criadas no form pai
IDCadastro := tabConsulta.fieldByName(´ID´).AsInteger;

// apenas altero as variaveis e crio o form
if not Assigned(frmCadFuncionarios) then
frmCadFuncionarios := TfrmCadFuncionarios.Create(self);

frmCadFuncionarios.ShowModal;
FreeAndNil(frmCadFuncionarios);
end;

e para add um novo funcionario apenas defino inserir=true e crio o form.As variaveis estao no form pai e sao usadas pelo form padrao consulta e cadastro. Quando crio o form cadastro ele excuta esse codigo:

//a tabela foi passada como parametro no formcreate
procedure TfrmMestreCadastro.AbreFormCad;
begin
if inserir Then//variavel usada nos forms conulta e cadastro
begin
tabCadastro.Cancel;//tabCadastro criada no form padrao cadastro
tabCadastro.Append;
tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);
end
Else
begin
tabCadastro.Close;
tabCadastro.FetchParams;
tabCadastro.Params.ParamByName(´pID´).AsInteger := IDCadastro;
tabCadastro.Open;
end;
end;

O problema esta nas variaveis INSERIR e IDCadastro,definidas no form pai. Elas deveriam ser alteradas no form consulta,mas,nao é possivel. Ta ai se alguem puder me ajudar!


Ednilson Campos

Ednilson Campos

Curtidas 0

Respostas

Rodc

Rodc

08/12/2008

é erro na compilação ou ao rodar?
A variável é pública na classe pai?


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

A variavel é publica e o erro é de execuçao, eu nao consigo alterar as variaveis,quando passo um parametro,um código por exemplo, o valor da variavel Integer nao muda fica sempre zero e a boolean sempre false. Cara ja fiz de tudo aki e nao da certo.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Ah sim...é na classe pai q foi declarada. Tentei declara-la no form padrao consulta e usar uma procedure dele msm, e tbm nao deu certo. Tambem tentei no form padrao cadastro e nao deu certo.


GOSTEI 0
Rodc

Rodc

08/12/2008

Será que a variável não está redeclarada na classe filha? Se você der um Ctrl+Click sobre a variável o cursor vai para a declaração correta?


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Cara a variavel altera o valor sim, um problema era q eu estava limpando os campos no momento errado,porem,o parametro q a variavel recebe no form consulta padrao nao é passado para o metodo q ta no form cadastro padrao. A parte de nao alterar ta corrigido, agora é só a questao do parametro entre os forms padrao.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Declarei apenas no formulario pai. Quando altero a variavel num formulario ela nao esta alterada no outro.


GOSTEI 0
Rodc

Rodc

08/12/2008

Qual formulário chama a função AbreFormCad() da classe pai? É nesta função que o valor de ´Insert´ não está correto?


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Quando to no formulario de consulta funcionarios por exemplo e clico em novo ou editar, altero as variaveis q estao no form pai,crio o form cadastro de funcionarios e nele tem o metodo abreformcad, nao to passando parametro pra ele, apenas utilizo as variaveis do fom pai q foram alteradas no form consulta. Nao consegui usar esse comando {frmMestreCadastro.AbreFormCad(inserir,pIDCadastro);} no form padrao consulta nem no consulta funcionarios, da esse erro {Access violation at address 00615EAB in module}.


GOSTEI 0
Rodc

Rodc

08/12/2008

Você tem que lembrar que dois formulários descenderem do mesmo pai não quer dizer que os dois compartilham das mesmas variáveis. As duas filhas apenas tem a mesma estrutura, porém na memória cada uma tem a sua variável ´Insert´ em local diferente da memória.
Se você tem Form1 e Form2 descendedo de TForm; ao colocar ´Form1.Visible := false´ não fará com que a variável ´Visible´ do Form2 também esteja como false apenas porque as duas descendem da mesma classe, correto?

Você não consegue chamar frmMestreCadastro.AbreFormCad() porque este formulário não está criado. É a mesma coisa de você tentar acessar uma função de um formulário qualquer (Form1, Form2, ...) que não foi criado ainda.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Certo ai por isso coloquei um TTimer e quando o form é criado ele executa o metodo usando as variaveis do form pai q foram alteradas no form consulta. Nao da erro mas as variaveis do form pai alterados no form consulta-fiz o teste e altera msm- nao vao para o form cadastro.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Parece q as variaveis sao restauradas quando abro o um formulario de cadastro, num sei pq.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Ah...não consigo msm,se alguem tiver outra forma ou sugestão de como fazer consulta e cadastro com Herança,eu agradeço!!


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Boa noite a todos.

Em primeiro lugar quando voce instancia um Form na memória, ao tentar instanciar o mesmo Form com a mesma variável novamente, ele dá o erro de Access Violation......

Isto ocorre porque o mesmo Form já se encontra em memória, voce deve sempre limpá-lo da memória com o método Free ou com a função FreeAndNil(Variável), ai sim voce pode instanciá-lo novamente em uma nova chamada.

Quanto a variáveis Inserir: Boolean, o nosso amigo Rodc está correto, apesar dela estar declarada no Form Ancestral (Pai), ao instanciar os Forms derivados (filhos), cada form filho terá a sua variável Insert com valores diferentes, com já foi dito pelo nosso amigo.

Para resolver esta questão, voce deverá implementar um método Inserir no Form Ancestral (Pai) e neste método atribuir o valor de Insert como True. Ao ser invocado o método Inserir nos Forms filhos, a variável Insert já é configurado automaticamente como True, isto é se você implementar também o método inserir nos forms filhos com a cláusula Inherited.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa tarde. Muito obrigado pelas dicas,mas,ainda não consegui fazer funcionar. Nao entendi muito bem como corrigir,criei o metodo inserir como vc disse:

procedure TfrmPai.NovoRegistro(ClasseForm: TFormClass;pID: Integer);
var
form : TForm;
begin
Try
application.CreateForm(ClasseForm,form);
inserir := true;//defini como true

tabCadastro.Cancel;//parametro q vem do formCadastro{aki ta dando o erro q vc disse sobre liberar da memoria{Acces Violation}
tabCadastro.Append;
tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);

form.ShowModal;
Finally
FreeAndNil(form);
End;
end;

No formulario de consulta chamo dessa forma:

procedure TfrmConsFuncionarios.btnNovoClick(Sender: TObject);
begin
inherited;
NovoRegistro(TfrmCadFuncionarios);//passo a Classe do formCadastro como parametro
end;

Evento quando o formCadastro é criado:

procedure TfrmCadFuncionarios.FormCreate(Sender: TObject);
begin
inherited;
dmCadFuncionarios := TdmCadFuncionarios.Create(Self);
dmCadFuncionarios.cdsCadastro.Open;
//passo os outros parametros{tabela e generator}
tabCadastro := dmCadFuncionarios.cdsCadastro;
Generator := ´GEN_FUNCIONARIOS_ID´;
end;

E e pra Editar tenho este metodo no form Pai:

procedure TfrmPai.Editar(pID: Integer);
var
ID : Integer;
begin
tabCadastro.Close;//aki tbm da o erro{Violaçao de Memoria}
tabCadastro.FetchParams;
tabCadastro.Params.ParamByName(´pID´).AsInteger := ID;
tabCadastro.Open;
end;

o metodo é chamdo da seguinte forma:

procedure TfrmConsFuncionarios.btnEditarClick(Sender: TObject);
begin
inherited;
Editar(tabConsulta.fieldByName(´ID´).AsInteger);//parametro para ediçao tbm nao consegui resolve essa parte
end;

As variaveis q utilizo:

public{todas no form Pai}
tabCadastro,tabConsulta : Tclientdataset;
sqlConsulta : TSQLQuery;

Generator : String;

inserir : Boolean;
pIDCadastro : Integer;

Agora tudo q utilizo ta ai espero q facilite pra vcs me ajudarem!


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Boa noite Kenshin.

Deixa eu te fazer uma pergunta:

Esse form Consulta está herdando do Form Pai :?:


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Fiz dessa forma: tenho o formPai,dele herdam o formMestreConsulta e o formMestreCadastro, todo formulario de consulta utiliza metodos do formPai e do formMestreConsulta. E todo formulario de cadastro herda do formPai e do formMestreCadastro.


GOSTEI 0
Micheus

Micheus

08/12/2008

Tanto no código que vc [url=http://scriptbrasil.com.br/forum/index.php?s=&showtopic=130025&view=findpost&p=522065]postou[/url] no forum [i:5b9df98b18]ScriptBrasil[/i:5b9df98b18], quanto no que postou aqui, percebo que vc inicializa o [i:5b9df98b18]tabCadastro[/i:5b9df98b18], no evento [i:5b9df98b18]OnCreate[/i:5b9df98b18] do form [i:5b9df98b18]TfrmCadFuncionarios[/i:5b9df98b18], a partir da atribuição do endereço do dataset que existe no datamodule [i:5b9df98b18]dmCadFuncionarios[/i:5b9df98b18], também criado neste evento. Isto deve estar funcionando bem para o caso de quando vc utilizar o botão de inclusão ([i:5b9df98b18]btnNovo[/i:5b9df98b18]) - ao menos em uma primeira execução - porque neste momento, vc chama o método [i:5b9df98b18]NovoRegistro[/i:5b9df98b18] da classe [i:5b9df98b18]TfrmPai[/i:5b9df98b18] o qual criará o form [i:5b9df98b18]frmCadFuncionarios[/i:5b9df98b18], que na seqüência será mostrado ([i:5b9df98b18]ShowModal[/i:5b9df98b18]) e, ao ser fechado o form, este será eliminado através da chamada [i:5b9df98b18]FreeAndNil[/i:5b9df98b18].

Entretanto, quando vc utiliza o botão [i:5b9df98b18]btnEditar[/i:5b9df98b18], o seu método [i:5b9df98b18]Editar[/i:5b9df98b18], simplesmente utiliza a variável [i:5b9df98b18]tabCadastro[/i:5b9df98b18] - que estará apontando para onde??? (Sabe-se lá. Esse o motivo do erro logo na primeira linha em que vc a referencia)

Acho que duas observações seriam pertinentes:
1) o [i:5b9df98b18]dmCafFuncionarios[/i:5b9df98b18], assim como o [i:5b9df98b18]frmCadFuncionarios[/i:5b9df98b18], deveria estar sendo liberado da memória - o que não consta do código (talvez, no [i:5b9df98b18]OnDestroy[/i:5b9df98b18] ou [i:5b9df98b18]OnClose[/i:5b9df98b18] do [i:5b9df98b18]frmCadFuncionarios[/i:5b9df98b18] vc esteja fazendo isto, mas não citou)
2) ao usar a opção de edição, pela lógica, vc deveria novamente criar o [i:5b9df98b18]frmCadFuncionarios[/i:5b9df98b18], o que criaria o [i:5b9df98b18]dmCadFuncionarios[/i:5b9df98b18] e inicializaria as variáveis dos datasets, e então, antes de chamar o [i:5b9df98b18]ShowModal[/i:5b9df98b18], posicionaria o dataset no registro desejado.

Abraços


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Bom dia! Os eventos q vc citou Ondestroy e OnClose estao codificados corretamente. O erro{ ´Access violation at address 004A5BEE in module ´SISACON.exe´. Read of address 00000000´} continua tanto no metodo inserir quanto no editar. O metodo para ediçao deve ser mais dificil de corrigir pq precisa de um parametro:

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer);
var
form : TForm;
begin
Try
application.CreateForm(ClasseForm,form);

tabCadastro.Close;// aki acontece o erro
tabCadastro.FetchParams;
tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
tabCadastro.Open;
form.ShowModal;
Finally
FreeAndNil(form);
End;
end;


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Ah sim...corrigi o metodo Editar!


GOSTEI 0
Micheus

Micheus

08/12/2008

Parece que ainda tem algo mais... :(
Os eventos q vc citou Ondestroy e OnClose estao codificados corretamente.
ou seja, em um deles, vc está usando algo como [i:568b66b34e]FreeAndNil(dmCadFuncionarios)[/i:568b66b34e]? Isto?!

Por acaso, nas opções de projeto, vc retirou lembrou de retirar os forms da auto-criação? (ficaria apenas o principal)


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Aop bao! Olha eu to utilizando o FreeAndnil(dmCadFuncionarios) e {Action := CaFree; frmCadFuncionarios := nil;} mas tem um porém eu estou com o form pricipal e o DataModule principal como auto-create sera q esse é o motivo dos erros? e onde q eu instanciaria o DataModule principal,no formPrincipal,no Source do meu projeto?


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Boa tarde a todos.

É como a lei de Murphy que aqui no caso: ´Será que existe algo a mais :?: ´

Sim tem algo ainda mais além do que o nosso Micheus citou, que aliás muito bem observado por ele.

A algo a mais a que me refiro, é que quando voce defini um Form Pai e tantos outros Forms Filhos derivados dele, para instanciar os Forms Filhos, o Form Pai não precisa estar instanciado em memória, isto porque o [color=darkblue:b3f508590f]Delphi define por padrão todos os métodos de uma classe como estáticos[/color:b3f508590f], assim a Form Pai funciona como se fosse um Form biblioteca.

Assim sendo, se voce está instanciando os Forms frmCadastro e frmConsulta, sendo estes os Forms pais de outros tantos, não há essa necessidade.

Caso não esteja fazendo isso, então voltamos ao ponto inicial citado pelo nosso Amigo Micheus, onde no Evento OnCreate do Form Pai voce cita que cria o dmCadastro contendo os DataSets. Portanto voce deve destruí-lo no Evento OnClose deste mesmo Form pai.

Entretanto eu vejo uma solução mais simples do que voce criar dois DataModules (dmCadastro e dmConsuta), pois quanto mais objetos instanciados, mais trabalho para controlá-los e destruí-los.

Qual é a sugestão então :?:

Simples, voce colocar apenas um DataSet e um DataSouce no primeiro Form Pai. Ora se os demais herdam deste Form pai, então vão também herdar o DataSet e o DataSource, onde cada DataSet e cada DataSource será independente em cada Form filho, nesse caso voce pode configurá-lo dentro de cada Form filho para abrir a sua tabela respectiva.

Qual é a vantagem disto. :?:

Pelo menos voce não precisa instaciar um ou dois DataModules, economizando memória, apenas o DataSet em cada Form Filho por ocasião da instanciação deste, além do que voce economiza recursos de contrôle em ter que estar instanciando DataModules e abrindo DataSets e depois fechando DataSets de destruindo DataModules. Valendo lembrar que voce só precisa abrir o DataSet que está em cada Form Filho, no evento OnCreate ou OnShow do Form Pai e fechá-lo no se evento OnClose.

Detalhe, deixe apenas um único DataModule ativo contendo apenas o IBDataBase e o IBTransaction.


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Boa tarde Kenshin

Só agora vi o seu último Post.

Ou voce utiliza Action := caFree;

Ou voce utiliza frmCadFuncionarios := nil;

Os dois juntos é claro que vai dar erro, pois logo na primeira chamada Action := caFree, a instância do Form será limpa, e quando fizer a segunda chamada (frmCadFuncionarios), ele vai limpar o quê :?:

Eu sugiro voce substituir esses dois métodos por FreeAndNil(frmCadFuncionarios) como voce utilizou com o dmCadFuncionarios, assim:

  ....
  FreeAndNil(dmCadFuncionarios)
  FreeAndNil(frmCadFuncionarios)
  ...



GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa noite pessoal! Vou falar o q ainda nao disse sobre problema acho q eu tenho postado sem todas as informaçoes necessarias. Bom estou fazendo dessa forma: tenho um data module para cada formulario de cadastro,um data module para cada formulario de consulta e em cada um deles tenho um ClientDataset,um DatasetProvider,um SQLqry e um DataSource;tenho um data module especifico contendo um sqlConection. Bom fiz assim pq o datamodule é mais leve do q os formularios e por isso coloquei o DataSource nele tbm. Quando nao preciso de parametros vindo do form pai funciona tudo blz grava,edita e consulta normal. Quanto a liberar da memoria nao expliquei direito os formularios faço assim:

procedure TfrmConsFuncionarios.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
inherited;
Action := CaFree;
frmConsFuncionarios := nil;
end;

e para os DataModules assim:

procedure TfrmConsFuncionarios.FormDestroy(Sender: TObject);
begin
inherited;
dmConsFuncionarios.cdsFuncionarios.Close;
FreeAndNil(dmConsFuncionarios);
end;

Agora outra duvida é sobre o DataModule de conexao estar sendo criado automaticamente,fica melhor msm se nao for assim,mas,onde devo instancia-lo no formPricipal ou no Source do projeto? Eu nao estou criando datamodule nos forms Mestres,a cada formulario criado seu respectivo datamodule é criado e liberado,seja de consulta ou de cadastro.


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Bom dia Kenshin.

O DataModule principal que contém o SQLConnection voce pode instanciá-lo no momento da inicialização do seu sistema.

Mas como eu faço isso :?:

Simples.

Vá no menu Project --> Options, voce vai abrir a ferramento ´Project Options for nome do seu projeto e vai encontrar dentro dela uma caixa combobox contendo o nome do Form principal que vai ser aberto logo de início e duas caixas de listagem, uma nominada Auto-Create Forms e Available Forms. O que estiver dentro de Auto-Create Forms é instanciado na inicialização do sistema, portanto, mova para Available Forms todos os Forms que voce não queira que seja instanciado (armazenado em memória) logo quando o seu sistema inicia, neste inclua-se os DataModules de Cadastro e Consulta. Deixe somente em Auto-Create Forms, o DataModule Principal e o Form Principal.

Agora quanto a instanciar os demais DataModules e Forms, voce precisa observar o seguinte:

Em seu primeiro post observei que voce em certas ocasiões está utilizando o método ShowModal desta Forma:


   Try
        application.CreateForm(ClasseForm,form);
        inserir := true;//defini como true

        tabCadastro.Cancel;
        tabCadastro.Append;
        tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);

        form.ShowModal;
   Finally
        FreeAndNil(form);  // Aqui voce destroi o Form
   End;
 


Ora se voce destroi o esse mesmo Form antes lá dentro do seu Evento OnClose, o que voce acha que vai acontecer com a instrução logo abaixo do ShowModal, isto quando ele tentar destruir o Form que já foi destruído. :?:

Então neste caso coloque tão somente dentro do Evento OnClose de cada Form Cadastro e Consulta, somente a destruição dos DataModules Cadastro e Consulta, assim:


procedure TfrmConsFuncionarios.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  inherited;
  dmConsFuncionarios.cdsFuncionarios.Close;
  FreeAndNil(dmConsFuncionarios); 
end;



E só, descarte totalmente o evento Destroy destes formulários


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Discorpio fiz as correçoes q vc falou. este post é apenas para confirmaçao!
Pessoal com a ajuda de vcs tenho corrigido alguns detalhes,muito obrigado! Ainda nao consegui corrigi os principais erros. Desculpa mas fica errado liberar o formulario dessa forma:

procedure TfrmCadFuncionarios.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
inherited;
Action := Cafree;
frmCadFuncionarios := nil;
end;

e por estar liberando o form como fiz acima nao posso liberar como ta logo abaixo

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer);
var
form : TForm;
begin
Try
application.CreateForm(ClasseForm,form);

tabCadastro.Close;
tabCadastro.FetchParams;
tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
tabCadastro.Open;
form.ShowModal;
Finally
FreeAndNil(form);//aki com o FreeAndNil(form)?vcs ja falaram mas sempre achei q fosse necessario fazer assim e tbm ja corrigi to so confirmando
End;
end;

e tbm liberar o datamodule de cadastro dessa forma:

procedure TfrmCadFuncionarios.FormDestroy(Sender: TObject);
begin
inherited;
dmCadFuncionarios.cdsCadastro.Close;
FreeAndNil(dmCadFuncionarios);
end;

Estou isntanciando o datamodule principal no form principal retirei do auto create:

procedure TfrmPrincipal.FormCreate(Sender: TObject);
begin
if not Assigned(dmPrincipal) then
dmPrincipal := TdmPrincipal.Create(Application);
end;

e liberando no OnClose

procedure TfrmPrincipal.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
inherited;
dmPrincipal.sqlconPrincipal.Connected := False;
FreeAndNil(dmPrincipal);
end;
Tem algo mais q posso fazer sobre o dmPrincipal,nao ta ando erro.
Agora o q resta msm é o formulario de cadastro q ao ser criado e Editando ou Inserindo ainda da erro na linha especificada abaixo::

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer);
var
form : TForm;
begin
Try
application.CreateForm(ClasseForm,form);

tabCadastro.Close;//aki violaçao de memoria{esse parametro vem do formCadFuncionarios no evento OnCreate}
tabCadastro.FetchParams;
tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
tabCadastro.Open;
form.ShowModal;
Except
End;
end;


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Essa é a Estrutura de Herança, representada pelo Micheus.

TfrmPai +--> TfrmMestreConsulta | +--> TfrmConsFuncionarios | +--> : | +--> : +--> TfrmMestreCadastro +--> TfrmCadFuncionarios


Estou liberando o DataModule no Evento OnClose como fui aconselhado:

procedure TfrmConsFuncionarios.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  dmConsFuncionarios.cdsFuncionarios.Close;
  FreeAndNil(dmConsFuncionarios);
end;


e agora os metodos Editar e Inserir estao assim:

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer);
var
  form : TForm;
begin
  Try
    application.CreateForm(ClasseForm,form);

  tabCadastro.Close;{o erro de violaçao de memoria continua}
  tabCadastro.FetchParams;
  tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
  tabCadastro.Open;

  form.ShowModal;
  Finally
    FreeAndNil(form);
  End;
end;

procedure TfrmPai.NovoRegistro(ClasseForm: TFormClass);
var
  form : TForm;
begin
  Try
    application.CreateForm(ClasseForm,form);

    tabCadastro.Cancel;{o erro de violaçao de memoria continua}
    tabCadastro.Append;
    tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);

    form.ShowModal;
  Finally
    FreeAndNil(form);
  End;
end;


Ao liberar um formulario com FreeAndNil(form) nao é preciso liberar tbm no OnClose correto?
Os parametros vem do Evento OnCreate como disse antes:

procedure TfrmCadFuncionarios.FormCreate(Sender: TObject);
begin
  inherited;
  dmCadFuncionarios := TdmCadFuncionarios.Create(Self);
  dmCadFuncionarios.cdsCadastro.Open;

  tabCadastro := dmFuncionarios.cdsFuncionarios;
  Generator   := ´GEN_FUNCIONARIOS_ID´;
end;


Seria errado fazer herança com DataModule assim:

TdmPai +--> TdmMestreConsulta | +--> TdmConsFuncionarios | +--> : | +--> : +--> TdmMestreCadastro +--> TdmCadFuncionarios


pq assim a manutençao seria mais facil. Codigos como esse por ex ficaria apenas no TdmMestreCadastro:

procedure TdmCadastro.dspCadastroBeforeUpdateRecord(Sender: TObject;
  SourceDS: TDataSet; DeltaDS: TCustomClientDataSet;
  UpdateKind: TUpdateKind; var Applied: Boolean);
begin
 if UpdateKind = ukInsert then
    if SourceDs = qryCadastro then
      Begin
        qryGen.Open;
          try
            DeltaDS.FieldByName(´ID´).NewValue := qryGen.FieldByName(´NOVO_ID´).Value;
            cdsCadastro.Edit;
            cdsCadastro.FieldByName(´ID´).Text := DeltaDS.FieldByName(´ID´).AsString;
          finally
        qryGen.Close;
      end;
    end;  
end;


Mas no momento a prioridade é fazer funcionar o Cadastro!
Valew t+!!![quote:80019f5fb2][/quote:80019f5fb2]


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa Noite! Discorpio quando vi seu ultimo post nao pude fazer as alteraçoes,ai o forum saiu do ar e agora q voltou seu post nao esta masi aki! vc poderia postar novamente por favor! É aquele q vc passou o DataModule como parametro!
Obrigado!


GOSTEI 0
Discorpio

Discorpio

08/12/2008

Boa tarde Kenshin.

Deculpe a demora, porém também achei estranho o meu último post ter sumido daqui, porém não importa, o que importa é que a última coisa que me lembro do meu último post é de ter te instruído a passar um TDataModule ao método por parâmetro. Contudo ao fazer mais um depuração do seu código vejo que isto não é necessário, vamos as considerações:

O Erro acontece aqui:

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer); var form : TForm; begin Try application.CreateForm(ClasseForm,form); [color=darkred:b0d9d1cf8b]tabCadastro.Close;{o erro de violaçao de memoria continua}[/color:b0d9d1cf8b] tabCadastro.FetchParams; tabCadastro.Params.ParamByName(´pID´).AsInteger := pID; tabCadastro.Open; form.ShowModal; Finally FreeAndNil(form); End; end; procedure TfrmPai.NovoRegistro(ClasseForm: TFormClass); var form : TForm; begin Try application.CreateForm(ClasseForm,form); [color=darkred:b0d9d1cf8b] tabCadastro.Cancel;{o erro de violaçao de memoria continua}[/color:b0d9d1cf8b] tabCadastro.Append; tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator); form.ShowModal; Finally FreeAndNil(form); End; end;


Agora veja o código que voce está instanciando no form filho de cadastro:

procedure TfrmCadFuncionarios.FormCreate(Sender: TObject); begin inherited; dmCadFuncionarios := TdmCadFuncionarios.Create(Self); [color=red:b0d9d1cf8b]dmCadFuncionarios.cdsCadastro.Open;[/color:b0d9d1cf8b] [color=red:b0d9d1cf8b] tabCadastro := dmFuncionarios.cdsFuncionarios;[/color:b0d9d1cf8b] Generator := ´GEN_FUNCIONARIOS_ID´; end;


Repare que neste último código você instancia o dmCadFuncionarios, e faz referência a tabCadastro com outro DataModule (dmFuncionarios) que nem instanciado está, ou seja, o sistema está aquardando voce instanciar o DataModule dmFuncionarios, ou será que voce digitou errado :?:

Dê uma verificada.


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Entao...aquele post ta errado msm,copiei errado, mas o codigo era esse aki:

procedure TfrmCadFuncionarios.FormCreate(Sender: TObject);
begin
  inherited;
  dmCadFuncionarios := TdmCadFuncionarios.Create(Self);
  dmCadFuncionarios.cdsCadastro.Open;

  tabCadastro := dmCadFuncionarios.cdsCadastro;
  Generator   := ´GEN_FUNCIONARIOS_ID´;
end;


Eu acredito q talvez tenha msm q passar o DM como parametro tbm,eu bem tentei mas nao consegui.Se vc poder postar novamente por favor!
Desde já Agradeço!!


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa tarde a todos!! Muito Obridago a todos q opinaram e ajudaram a resolver!!

Fiz algumas alteraçoes e queria a opiniao de vcs! Pra resolve a questao q ja se prolonga eu apenas instanciei o DM de Cadastro juntamente com o de Consulta assim:

procedure TfrmConsFuncionarios.FormCreate(Sender: TObject);
begin
  inherited;
  dmConsFuncionarios := TdmConsFuncionarios.Create(Self);
  dmConsFuncionarios.cdsFuncionarios.Open;

  dmCadFuncionarios := TdmCadFuncionarios.Create(Self);
  dmCadFuncionarios.cdsCadastro.Open;

  tabCadastro := dmCadFuncionarios.cdsCadastro;
  Generator   := ´GEN_FUNCIONARIOS_ID´;

  tabConsulta := dmConsFuncionarios.cdsFuncionarios;
  sqlConsulta := dmConsFuncionarios.qryFuncionarios;
  
  NomeTabela := ´FUNCIONARIOS´;
  NomeCampo := ´NOME´;

  NomeTabelas.Caption := ´FUNCIONARIOS´;
  NomeCampos.Caption  := ´NOME´;
end;


Ai é só chamar no enveto dos botoes Editar ou Inserir:

procedure TfrmConsFuncionarios.btnEditarClick(Sender: TObject);
begin
  Editar(TfrmCadFuncionarios,tabConsulta.fieldByName(´ID´).AsInteger);
  inherited;
end;

procedure TfrmConsFuncionarios.btnNovoClick(Sender: TObject);
begin
  inherited;
  NovoRegistro(TfrmCadFuncionarios); //Registros(TfrmCadFuncionarios,INSERIR,tabConsulta.fieldByName(´ID´).AsInteger,tabCadastro);
end;


O codigo do Metodo Editar:

procedure TfrmPai.Editar(ClasseForm: TFormClass;pID: Integer);
var
  form : TForm;
begin
  application.CreateForm(ClasseForm,form);

  tabCadastro.Close;
  tabCadastro.FetchParams;
  tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
  tabCadastro.Open;

  form.ShowModal;
end;


O metodo Inserir é semelhante a este acima. Tive problemas pra liberar da memoria por isso vou postar tbm o OnClose:

procedure TfrmConsFuncionarios.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  dmConsFuncionarios.cdsFuncionarios.Close;
  FreeAndNil(dmConsFuncionarios);

  dmCadFuncionarios.cdsCadastro.Close;
  FreeAndNil(dmCadFuncionarios);
  
  FreeAndNil(frmConsFuncionarios);
end;


A duvida é...existe algum problema em instanciar dois DataModules num mesmo Formulario como fiz acima? Ficaria melhor se pudesse deixar cada Formulario instanciando e liberando da memoria seus respectivos DataModules?


GOSTEI 0
Micheus

Micheus

08/12/2008

A duvida é...existe algum problema em instanciar dois DataModules num mesmo Formulario como fiz acima?
No meu modo de ver, problema não há. Mas, seria mais prático (menos sujeito a erros) o uso da sugestão do colega [b:7a4db5d2bd]Discorpio[/b:7a4db5d2bd] neste [url=http://forum.devmedia.com.br/viewtopic.php?p=323848#323848]post[/url]: [i:7a4db5d2bd]´colocar apenas um DataSet e um DataSouce no primeiro Form Pai. (...)´[/i:7a4db5d2bd]

procedure TfrmPai.Editar(ClasseForm: TFormClass; pID: Integer);
var
  form : TForm;
begin
  application.CreateForm(ClasseForm,form);

  tabCadastro.Close;
  tabCadastro.FetchParams;
  tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
  tabCadastro.Open;

  form.ShowModal;
end;

procedure TfrmConsFuncionarios.btnEditarClick(Sender: TObject);
begin
  Editar(TfrmCadFuncionarios, tabConsulta.fieldByName(´ID´).AsInteger);
  inherited;
end;

[b:7a4db5d2bd]Kenshin[/b:7a4db5d2bd], voce não postou como ficou o código no [i:7a4db5d2bd]OnClose[/i:7a4db5d2bd] do form [i:7a4db5d2bd]TfrmCadFuncionarios[/i:7a4db5d2bd], mas se ele ainda está como citado em post anterior (código abaixo) ele não está correto, a menos que vc tenha deixado apenas a linha [i:7a4db5d2bd]Action := caFree[/i:7a4db5d2bd]. Isto porque, baseado no processo de criação do form (código acima), a variável [i:7a4db5d2bd]frmCadFuncionarios[/i:7a4db5d2bd] não é utilizada e não corresponde à memória alocada para este form, visto que vc usa (acertadamente) uma instância local ao procedimento que o cria, lá no método [i:7a4db5d2bd]Editar[/i:7a4db5d2bd]:
procedure TfrmCadFuncionarios.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  inherited;
  Action := Cafree;
  frmCadFuncionarios := nil;
end; 

Outra coisa, se o [i:7a4db5d2bd]dmCadFuncionarios[/i:7a4db5d2bd] é usado apenas no [i:7a4db5d2bd]frmCadFuncionarios[/i:7a4db5d2bd], o mais apropriado é que este form crie e libere o referido datamodule.

Vale lembrar o que o colega [b:7a4db5d2bd]Discorpio[/b:7a4db5d2bd] citou neste [url=http://forum.devmedia.com.br/viewtopic.php?p=323848#323848]post[/url]: [color=darkblue:7a4db5d2bd][i:7a4db5d2bd]´o Delphi define por padrão todos os métodos de uma classe como estáticos´[/i:7a4db5d2bd][/color:7a4db5d2bd]
Caso vc não estivesse utilizando as variáveis dos datamodules criadas pelo Delphi, seus forms de cadastro não funcionariam.
Apesar de vc instanciar localmente o form de cadastro (não usar a variável global, criada pelo Delphi), os componentes data-aware do form de cadastro continuam apontando para os datasources contidos naquelas datamodules.

Abraços


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa Noite!
Quando eu instancio o [b:0c0fa69fed]Data Module de Cadastro no Formulario de Cadastro[/b:0c0fa69fed] da erro na [b:0c0fa69fed]Tabela[/b:0c0fa69fed] q passo como parametro. Ao instanciar o [b:0c0fa69fed]Data Module de Cadastro no Formulario de Consulta[/b:0c0fa69fed] nao da erro. Eu nao consegui mas queria muito deixar cada Formulario cuidar de seu proprio Data Module.Da forma q eu fiz todo [b:0c0fa69fed]Formulario de Consulta[/b:0c0fa69fed] vai isntanciar dois Data Modules(Consulta e Cadastro) queria mudar isso. O metodo q instancia qualquer Formulario de Consulta fica no form Pai:
Procedure TfrmPai.CriaForm(ClasseForm: TFormClass);
var
  form : TForm;
Begin
  application.CreateForm(ClasseForm,form);
  form.ShowModal;
end;

Para Cadastro tbm é no form Pai:
procedure TfrmPai.NovoRegistro(ClasseForm: TFormClass);
var
  form : TForm;
begin
  application.CreateForm(ClasseForm,form);
  tabCadastro.Cancel;
  tabCadastro.Append;
  tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);
  form.ShowModal;
end;

O OnClose de Cadastro:
procedure TfrmCadFuncionarios.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  //ta comentado pq esta sendo instanciado no Form Consulta

  //dmCadFuncionarios.cdsCadastro.Close; 
  //FreeAndNil(dmCadFuncionarios);
  FreeAndNil(frmCadFuncionarios);//neste caso libero apenas o Formulario
end;

Para cada formulario de Consulta tenho um DM,para cada Form de Cadastro tenho outro DM.
Para cada Tabela no Data Module utlizo :
[b:0c0fa69fed]Um ClientDataset,um DatasetProvider, um SQLQruery e um DataSource [/b:0c0fa69fed]
Espero ter clariado mais meu problema q foi resolvido,mas como o Micheus disse
nao ha problema
porem nao me parece muito correto(falo sobre instanciar dois DMs num msm Formulario)
Nao entendo pq da erro quando instancio o [b:0c0fa69fed] Data Module no Form Cadastro[/b:0c0fa69fed] e nao da erro quando instancio no [b:0c0fa69fed] Form Consulta????[/b:0c0fa69fed]
Abraço!!


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Pessoal eu tentei fazer como o Discorpio disse ´passar o DM como parametro´ e nao consegui tbm tentei colocar um dataset e um data source no FormPai e ele da erro pedindo um Provider?


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Pessoal,ate q enfim...
Nossa tantas alteraçoes foram feitas...e pra resolver apenas declarei as variaveis q preciso acima do implementation:
var
  frmPai: TfrmPai;

  tabCadastro,tabConsulta : Tclientdataset;
  sqlConsulta : TSQLQuery;

  Generator  : String;

  pIDCadastro : Integer;
  pRegistro   : Boolean;

implementation


E mais agora posso usar apenas um metodo para Editar ou Inserir:
procedure TfrmPai.Registros(ClasseForm: TFormClass;pNovo: Boolean;pID: Integer);
var
  form : TForm;
Begin
  Try
    application.CreateForm(ClasseForm,form);
    if pNovo then
    begin
      tabCadastro.Cancel;
      tabCadastro.Append;
      tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);
      form.ShowModal;
    end
    else
    begin
      tabCadastro.Close;
      tabCadastro.FetchParams;
      tabCadastro.Params.ParamByName(´pID´).AsInteger := pIDCadastro;
      tabCadastro.Open;
      form.ShowModal;
    end;
  Except
     //
  End;
end;

Discorpio,Micheus e os outros valew,valew msm!! Vo faze festa depois dessa...
Muito Obrigado!


GOSTEI 0
Micheus

Micheus

08/12/2008

Para Cadastro tbm é no form Pai:
procedure TfrmPai.NovoRegistro(ClasseForm: TFormClass);
var
  form : TForm;
begin
  application.CreateForm(ClasseForm,form);
  tabCadastro.Cancel;
  tabCadastro.Append;
  tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);
  form.ShowModal;
end;
O OnClose de Cadastro:
procedure TfrmCadFuncionarios.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  //ta comentado pq esta sendo instanciado no Form Consulta

  //dmCadFuncionarios.cdsCadastro.Close; 
  //FreeAndNil(dmCadFuncionarios);
  FreeAndNil(frmCadFuncionarios);//neste caso libero apenas o Formulario
end;
[b:bc384c6a27]Kenshin[/b:bc384c6a27], aqui vc confirmou o que eu supus (no [url=http://forum.devmedia.com.br/viewtopic.php?p=324345#324345]post[/url] anterior) que vc estivesse fazendo: é errado vc liberar [i:bc384c6a27]frmCadFuncionarios[/i:bc384c6a27], visto que vc não usa esta variável global (definida na unit do form). Note que vc cria o form de cadastro via método [i:bc384c6a27]NovoRegistro[/i:bc384c6a27] da classe [i:bc384c6a27]TfrmPai[/i:bc384c6a27] e a variável que recebe a instância do cadastro é a variável local [i:bc384c6a27]Form[/i:bc384c6a27].


Pessoal,ate q enfim... Nossa tantas alteraçoes foram feitas...e pra resolver apenas declarei as variaveis q preciso acima do implementation:
var
  frmPai: TfrmPai;

  tabCadastro,tabConsulta : Tclientdataset;
  sqlConsulta : TSQLQuery;

  Generator  : String;

  pIDCadastro : Integer;
  pRegistro   : Boolean;

implementation
[b:bc384c6a27]Kenshin[/b:bc384c6a27], este tipo de declaração torna suas variáveis globais. Assim, qualquer instância de um form descendente de [i:bc384c6a27]TfrmPai[/i:bc384c6a27] estará acessando o mesmo endereço, o que pode resultar em problemas quando vc tiver instanciados mais que um form de cadastro ou consulta. Pode até estar funcionando neste momento, mas em breve vc acabará tendo problemas. Faça alguns testes.

Abraços


GOSTEI 0
Ednilson Campos

Ednilson Campos

08/12/2008

Boa tarde!!!
Bom como vc disse esta acontecendo um erro,mas,é de vez enquando.Em tempo de programaçao,ao abrir um formulario qualquer durante o desenvolvimento da um erro de violaçao de memoria e em tempo de execuçao ainda nao deu erro. E msm eu instanciando o formulario de consulta com um metodo diferente do formulario de cadastro eu terei problemas? Nenhum formulario de Consuta deu erro ate o momento apenas os de Cadastro. Voltei as declaraçoes anteriores para Public

  private
    { Private declarations }
  public
    tabCadastro,tabConsulta : Tclientdataset;
    sqlConsulta             : TSQLQuery;
    Generator               : String;

var
  frmPai: TfrmPai;
  //tabCadastro,tabConsulta : Tclientdataset;

implementation


Para instanciar os formularios de consulta estou utilizando o metodo abaixo:
Procedure TfrmPai.CriaForm(ClasseForm: TFormClass);
var
  form : TForm;
Begin
  //Cria os formularios de consulta
  application.CreateForm(ClasseForm,form);
  form.ShowModal;
  FreeAndNil(form);//estou na duvida onde fica melhor liberar o form aki ou no OnClose?
end;

procedure TfrmClientes.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  inherited;
  dmClientes.cdsCadastro.Close;
  dmClientes.cdsCidades.Close;
  FreeAndNil(dmClientes);
  Action := CaFree;//esta é a forma correta?
end;

Para os formularios de cadastro como postei anteriormente tenho este metodo:
procedure TfrmPai.Registros(ClasseForm: TFormClass;pNovo: Boolean;pID: Integer);
var
  form : TForm;
Begin
  Try
    application.CreateForm(ClasseForm,form);
    if pNovo then
    begin
      tabCadastro.Cancel;
      tabCadastro.Append;
      tabCadastro.FieldByName(´ID´).AsInteger := GenProximoID(Generator);
      form.ShowModal;
    end
    else
    begin
      tabCadastro.Close;
      tabCadastro.FetchParams;
      tabCadastro.Params.ParamByName(´pID´).AsInteger := pID;
      tabCadastro.Open;
      form.ShowModal;
    end;
  Except
     //
  End;
end;


Voces nao poderiam passar um hexemplo de herança utilizando componentes DBExpress?[/u]


GOSTEI 0
POSTAR