Erro ao chamar MDIChild

Delphi

08/06/2005

Oi gente!

É a primeira vez que estou usando MDIFrom e MDIChild.
O MDIForm é o primeiro a ser criado na aplicação. Só que qdo chamo qualquer outro form configurado como MDIChild o delphi retorna o seguinte erro:

´CANNOT CREAT FORM. NO MDI FORMS ARE CURRENTLY ACTIVE´

Tem algum segredo ou propriedade especial pra usar esse esquema?


Michelle

Michelle

Curtidas 0

Respostas

Marco Salles

Marco Salles

08/06/2005

Tem algum segredo ou propriedade especial pra usar esse esquema?


Tem alguns detalhes , mas como vce esta chamando esse formularios
Filhos.. Qual é o seu código para a criação e para destruição dos formulários filhos :?: :?: :?:

Poderia postar :?: :?:


GOSTEI 0
Sérgio Gobbo

Sérgio Gobbo

08/06/2005

Eu faço assim:
Não crio os filhos automaticamente (Project/Options - tira ele do auto-create)
No menu do formulario pai, ao inves de chamá-lo com show, crio ele: Application.CreateForm(TForm1,form1); - tem que colocar o nome da unit no uses do pai tb
No evento OnClose do filho, vc destrói ele com:
Action:=caFree;
form1:=nil;
E é claro, não esquecer de colocar a propriedade formstyle do filho como child, claro.

Acho q se vc fizer assim dará certo.

FLLW


GOSTEI 0
Michelle

Michelle

08/06/2005

Eu faço assim: Não crio os filhos automaticamente (Project/Options - tira ele do auto-create) * Jú, se me permite a liberdade de chamá-lo assim, tenho outra dúvida: o form pai tem que, necessariamente, ser criado no auto create? Isso porque, fiz o seguinte teste: - Em uma nova aplicação só coloquei dois forms, frMDIForm e fr MDIchild e ao chamar o filho da maneira citada por vc abaixo, não deu erro algum com o pai sendo criado no auto-create. A questão é que na aplição em questão meu formulário pai só é criado depois de 2 outros formulários e está sendo criado no evento onclick do formulário antecessor da mesma maneira abaixo. Acho que aí é que está o problema pois o erro gerado pelo delphi diz que não pode criar o form filho pois não existe form pai ativo. É isso mesmo? No menu do formulario pai, ao inves de chamá-lo com show, crio ele: Application.CreateForm(TForm1,form1); - tem que colocar o nome da unit no uses do pai tb No evento OnClose do filho, vc destrói ele com: Action:=caFree; form1:=nil; E é claro, não esquecer de colocar a propriedade formstyle do filho como child, claro. Acho q se vc fizer assim dará certo. FLLW



GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

A questão é que na aplição em questão meu formulário pai só é criado depois de 2 outros formulários e está sendo criado no evento onclick do formulário antecessor da mesma maneira abaixo.


:idea: :idea:
Uma tentativa que em muitas situaçoes da certo serai alterar tb o FormStyle dos outros dois formulários que antecede o Formulafio em questão

Assim fazer

FormAntecessor.FormStyle:=fsMDIForm;

:arrow: [b:2e18d4cee5]Nesta situação voce pode deixar as coisas como estão[/b:2e18d4cee5] :
A questão é que na aplição em questão meu formulário pai só é criado depois de 2 outros formulários e está sendo criado no evento onclick do formulário antecessor da mesma maneira abaixo.


Acho que o junior_gobbo não vai importar de voce chama-lo assim:
Jú, se me permite a liberdade de chamá-lo assim

Ele vai ater gostar , eu acho......Se voce eu , eu gostaria :lol: :lol:


GOSTEI 0
Massuda

Massuda

08/06/2005

[quote:15d6d94027=´Marco Salles´]
A questão é que na aplição em questão meu formulário pai só é criado depois de 2 outros formulários e está sendo criado no evento onclick do formulário antecessor da mesma maneira abaixo.

...
alterar tb o FormStyle dos outros dois formulários que antecede o Formulafio em questão para

FormAntecessor.FormStyle:=fsMDIForm;[/quote:15d6d94027]Talvez isso não funcione. Um aplicativo MDI só pode ter um form ativo com estilo fsMDIForm (afinal, esse [b:15d6d94027]é[/b:15d6d94027] o form principal do programa).

A abordagem correta seria (auto)criar o form principal primeiro.

Provavelmente esses dois forms que hoje são criados primeiro podem sem problemas ser criados no OnCreate do form principal (especialmente se forem para login, splash window, etc). Um tópico similar está [url=http://www.forumweb.com.br/foruns/index.php?showtopic=29730]aqui[/url]


GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

--------------------------------------------------------------------------------

Marco Salles escreveu: Michelle escreveu: A questão é que na aplição em questão meu formulário pai só é criado depois de 2 outros formulários e está sendo criado no evento onclick do formulário antecessor da mesma maneira abaixo. ... alterar tb o FormStyle dos outros dois formulários que antecede o Formulafio em questão para


Massuda escreveu
FormAntecessor.FormStyle:=fsMDIForm; Talvez isso não funcione. Um aplicativo MDI só pode ter um form ativo com estilo fsMDIForm (afinal, esse é o form principal do programa).


Massuda, voce esta coberto de razão ,no que toca o conceito.. Eu esqueci de colocar o conceito..

[b:67d8709046]A abordagem correta seria (auto)criar o form principal primeiro[/b:67d8709046]


... Mas funcionar , pode acreditar, que talvez funcione....Faça um teste.


GOSTEI 0
Michelle

Michelle

08/06/2005

Acho que o junior_gobbo não vai importar de voce chama-lo assim:


Marquinho (só pra vc não ficar com ciúme), valeu a atenção!
Vi que essa questão já foi bastante discutida no fórum e que na maioria das vezes ninguém apresentou um código funcional.
No meu caso, a dificuldade é a seguinte:
meu primeiro form a ser startado pela aplicação, é um form que contém vários alíases, pois o sistema que desenvolvi aqui na empresa onde trabalho, permiti ao usuário acessar a base de dados do cliente desejado antes de iniciar o programa.
Selecionada a base desejada, é a vez de startar um splash de abertura que fica ativo enqto, paralelo a ele, meu form DataModule tb é criado e a base de dados escolhida é carregada.
Depois da base carregada entra o form de login pra só então entrar o form principal que é o meu MDI form.

Complicado? Ai, tomara que esteja sendo clara. Não sou muito boa nisso!

Bjinho


GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

Olha so...

[b:62deaa6250]Como o massuda disse,[/b:62deaa6250]

Crie o Form principal primeiro .....


(Project/Options - coloque ele do auto-create)...

Apresente o form com o aliase primeirO.. eu acho que basta colocar este form antes no projeto assim:::

   Application.Initialize;
   Application.CreateForm(TForm2, Form2); //form com o aliase
                                                             //Outros forms
   Application.CreateForm(TForm1, Form1);
  Application.Run;


Por ultimo depos da senha e so apresentar o Formprincipal ao inves de cria-lo...

Vi que essa questão já foi bastante discutida no fórum e que na maioria das vezes ninguém apresentou um código funcional.


As pessoas apresentam sim , so que muitas das vezes é dificil entender o que realmente se esta passando...

Quando dá errado , não se pode desistir..Quando da certo tem que postar dando Ok.. Muitas pesoas abandonan o tópico, ficando todo mundo sem saber se foi resolvido ou se a pessoa desistiu.. Com isto não se evolui :cry: :cry:

Boa sorte...


GOSTEI 0
Michelle

Michelle

08/06/2005

Crie o Form principal primeiro ..... (Project/Options - coloque ele do auto-create)... Apresente o form com o aliase primeirO.. eu acho que basta colocar este form antes no projeto assim:::
   Application.Initialize;
   Application.CreateForm(TForm2, Form2); //form com o aliase
                                                             //Outros forms
   Application.CreateForm(TForm1, Form1);
  Application.Run;
Por ultimo depos da senha e so apresentar o Formprincipal ao inves de cria-lo... Boa sorte...


Depois de seguir os passos acima, o erro continuou sendo gerado, então mudei a propriedade dos forms que devem abrir antes do Principal para MDI form e o erro parou de ser gerado.
Só que agora o problema é que ele cria os forms MDIchild, mas não mostra os mesmos na tela. Isso acontece qdo chamo os MDI Child com o comando Show. Já qdo uso ShowModal gera o erro ´Cannot make visible window´.
Ninguém merece, né!? Tem alguma sugestão?


GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

Ninguém merece, né!?


quem te dize que seria fácil...

Vamos fazer o seguinte...

Deixar os form asntes do principal com a propriedade FormSttle:=fsNormal
Deixar o FormPrincipal com a Propriedade
FormSttle:=fsMDIForm
Como era antes...

[b:667ba15744]coloque o formPrincipal para ser criado automaticamente (Project/Options - do auto-create)..Agora inverta a ordem na criação[/b:667ba15744]

A Diferença vem agora

Application.Initialize;
Application.CreateForm(TForm2, Form2); // FormPrincipal vem antes
// Outros forms .. etc...
Application.CreateForm(TForm1, Form1);
form1.Show;
Application.Run;

se voce não for usar mais os form que antecedem o formPrincipal , voce deve destri-los...Acho que pode ser feito na própia chamada

por exemplo

procedure TFormAtual.Button1Click(Sender: TObject);
begin
FormPrincipal.Show;
freeandnil(formatual); 
end;


Assim voce libera memoria.. Mas esta parte é melhor pedir a opinião do massuda, ele e teorico e pode orientar a melhor maneira de voce liberar estes forms caso voce não os utilize mais

Durante esse passos , os form são apresentados e os anteriores destruidos...

Ate que o ultimo form de login , apos a validação da senha , chama o formPrincipal e consequentemente se autoDestroe, digamos assim

procedure TFormLogin.Button1Click(Sender: TObject);
begin
se senha correta
begin
  FormPrincipal.Show;
  freeandnil(formaLogin); 
end
else
  application.terminate;
end;




Obs::: O Unico incoveniente desse modo e que o form principal , mesmo que ele não fique imediatamente ativo, ele ainda esta visivel e pode ser acessado.. Então sugiro que estes forms anteriormente criados tenham algumas propriedades que irão minimizar e impedir que isto venha a ocorrer

1)No evento onshow deles escreva o seguinte código:
 DeleteMenu(GetSystemMenu(Handle, False), SC_MOVE, MF_BYCOMMAND);//Nao deixa arrastar o form


2) Não deixe propriedade que permitem minimizar estes forms.. 
No objecto inspector va em BorderIcons e escolha BiMiniminize e BiMaximize cetado em false...


3) No evento onclose desses formulários que antecedem o Principal
escrever o seguinte...
application.terminate;


Note que fechar é diferente de destruir

4) Note que a posição e o tamanho desse form que antecedem o Formulário Principal, deve ser cuidadosamenente estudado , para não dar um efeito visual desagradavel


5)Dica.. como o form de login geralmente é  é pequeno , sugiro que ele seje parte de outro form, se quiser de passo uma dica show para criaçõa desse form de login


6) porque to preocupado com essas dicas... Rode a aplicação sem esse passos e voce ira perceber que com oo formPrincipal foi criado , voce podera acessa-lo .. ja que  o formularios anteriores , não podem ser criados na formashowmodal


7) Todas esses passos puderiam ser evitados se voce estivesse trabalhando com o modo clássico na criação e destruição dos formulário MDI...


8) Acho que não to esquecendo de nada eu ..To sem o delphi aqui para testar :cry: :cry: :cry: .. Mas amanha voce testa e comunique os posíveis erros.. .. :cry: :cry: :cry:

boa sorte...

:cry:


GOSTEI 0
Sérgio Gobbo

Sérgio Gobbo

08/06/2005

Para fazer isso, sem que o form principal fique aparecendo, faça o seguinte: (já testei)

faça como o Marco Salles disse, e crie primeiro o form principal: (para isso, vá em View/Project Manager, clique com o botão direito no nome do projeto, Project1.exe por exemplo, e escolha View Source)

begin
Application.Initialize;
Application.CreateForm(TForm2, Form2); //este seria o form principal, MDIForm
Application.CreateForm(TForm1, Form1);//form da tela de splash
form1.showmodal;// com esse showmodal o form pai (MDIForm) não aparecerá
Application.Run;
end.

Como o form1 é a tela de splash, ele não precisa ter barra de titulo (propriedade BorderStyle deve ser bsNone). Sem a barra de titulo o botão fechar não aparece, não deixando o usuario fechá-lo (pois caso ele fechasse, o form1 (pai) apareceria)
No evento q faz a tela de splash sumir, você programa:

form2.show;
form1.close;

Depois programe no OnCreate do Form Principal (pai) a destruição e liberação de memória do form1 fechado a pouco:

freeandnil(form1);

Pronto, desta maneira o 1º form a aparecer seria o da tela de splash e o form pai não apareceria enquanto o splash estivesse aparecendo, e o pai seria o principal, evitando o erro na hora de criar os forms filhos.

No caso da tela de login, vc tanto poderia chama-la após o splash ser descarregado, mas aí destruindo o splash no onCreate do form login e destruindo o form login no OnCreate do Pai; como poderia chamar o form de login dentro do pai, como form filho, e de acordo com o usuario, habilitar apenas oq este pode acessar do sistema.

Espero ter podido te ajudar Mi (hehe)

T+


GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

ju para lá Mi para cá , isto ja esta virando amizade e to vendo que vou ser o padrinho...

Mas vamos lá :

Duas coisas que gostaria que voce revisse....

Eu não sei com voce definiu a propriedade formSytle desses formulários ,
que antecedem ao formulário Principal....Mas se não me engano a Intrução
form1.showmodal;// com esse showmodal o form pai (MDIForm) não aparecerá

Da erro...
Por isto que eu disse anteriormente :::
ja que o formularios anteriores , não podem ser criados na formashowmodal


a segunda , e o seguinte .. Voce esta destruindo os formsecuncadários , logo no oncreate do formPrincipal... Este form é o primeiro a ser criado e portando a instrução
freeandnil(form1);

Não tera o efeito desejado... Erro na execução , não acredito , pois esta instrução testa antes de destruir , mas como esses formulários ainda não foram criados , ele simplesmente não os destroi

Isto são apenas conjunturas.. E devem ser levados com o intuito de somar. So isso.


GOSTEI 0
Sérgio Gobbo

Sérgio Gobbo

08/06/2005

[quote:06ec27d44c=´Marco Salles´]
Eu não sei com voce definiu a propriedade formSytle desses formulários ,
que antecedem ao formulário Principal....Mas se não me engano a Intrução
[/quote:06ec27d44c]

O formstyle dos antecessores ao pai estão como fsNormal

Citação: form1.showmodal;// com esse showmodal o form pai (MDIForm) não aparecerá Da erro...


Não dá erro não, já testei e funcionou perfeitamente.

a segunda , e o seguinte .. Voce esta destruindo os formsecuncadários , logo no oncreate do formPrincipal... Este form é o primeiro a ser criado e portando a instrução [quote:06ec27d44c]freeandnil(form1);

Não tera o efeito desejado... Erro na execução , não acredito , pois esta instrução testa antes de destruir , mas como esses formulários ainda não foram criados , ele simplesmente não os destroi
[/quote:06ec27d44c]

Neste caso eu me equivoquei, com a instrução no Oncreate, não apresenta erro, porém realmente não destrói.
No caso não sei onde por esta instrução, pois colocando-a no evento close do secundário, ou no show do pai, apresenta erro.
Sendo apenas 1 form secundario, poderia-se deixa sem destruir mesmo, pois ficaria funcional e de acordo com a descrição.

ju para lá Mi para cá , isto ja esta virando amizade e to vendo que vou ser o padrinho...


hehe... se ela topar...

T+


GOSTEI 0
Michelle

Michelle

08/06/2005

Oi!

Desculpem-me por não ter respondido antes. Meu final de semana foi um tumulto e ontem meu chefe iniciou a segunda feira com uma disposiçào assustadora.
Bom, mas agora estou mais sossegada e venho através deste dar a feliz notícia de que finalmente deu tudo certo.
Graças as dicas de vcs, organizei minhas idéias e consegui fazer o que queria.
Os passos foram:

1º) Forms antecessores ao frPrincipal -> FormStyle=fsNormal;
Form Principal-> FormStyle=MDIform;
Forms Filhos-> FormStyle=MDIChild;

2º) Form frPrincipal único indicado para criaçào automática -> (Project / Options/ Auto-Create forms);

3º) O segredo é realmente destruir e liberar todos os forms ancestrais (profundo né!?) ao frPrincipal no momento da criação de qualquer frFilho, garantindo neste momento que o único form ativo seja o frPrincipal;

4º) Estava pecando num detalhe: dependia de informações atreladas à alguns componentes pertencentes aos forms antecessores. O que me impedia de destruir realmente esses forms. Passei toda a informaçào para variáveis e matrizes públicas e resolvi essa questão.

Daí organizei a criação dos meus forms da seguinte maneira:

Em (Project-> View Source):

Application.CreateForm(TfrmPrincipal, frmPrincipal);
Application.Initialize;
Application.Name:= ´Teste MDI´;
Application.Title := ´MDI´;
Application.CreateForm(TfrmSeleAlias, frmSeleAlias);
frmSeleAlias.ShowModal;
Application.CreateForm(TfrmEntrada, frmEntrada);
frmEntrada.Show;
Application.CreateForm(TDM, DM);
frmEntrada.Hide;
frmEntrada.Free;
Application.CreateForm(TfrmSenhaAcesso, frmSenhaAcesso);
frmSenhaAcesso.ShowModal;
Application.Run;

procedure TfrmSeleAlias.BitBtn1Click(Sender: TObject);
begin
alias:=combobox1.Text;
frmSeleAlias.Close;
end;

procedure TfrmSeleAlias.FormClose(Sender: TObject;
var Action: closeAction);
begin
action:=cafree;
FrmSeleAlias:=Nil;
end;

O mesmo valeu pro restante dos forms iniciais. Dando o comando Close no evento OnClick e realizando a destruição e liberação no OnClose.

Agora a aplicaçào está redondinha. A não ser pelo fato de que ao abrir vários forms filhos e depois mandar organizar a janela com os comandos:
Cascade, tilemode:=tbhorizontal, tilemode:=tbvertical e arrangeicons, os forms minimizam ficando parcialmente visíveis, mas sem poder aumentar o tamanho deles e nem manipulá-los como se tivessem sido organizados pelo excell por exemplo.

Mas acho que já estou abusando né!?

Valeu mais uma vez pela paciência de vcs.

Ah, e sobre a questão:

Virando amizade...padrinho ... se ela topar...


gostaria de pronunciar que: ´Já estou envolvida! Se o Jú pular... tb pulo!´ (plagiei do Leo di Caprio em Titanic).

Só pra descontarir tá!?

Bjos pra vcs! Até a próxima! :P


GOSTEI 0
Marco Salles

Marco Salles

08/06/2005

Bom, mas agora estou mais sossegada e venho através deste dar a feliz notícia de que finalmente deu tudo certo.


ficamos felizes por isto...

Vi que essa questão já foi bastante discutida no fórum e que na maioria das vezes ninguém apresentou um código funcional.


Viu que não é tanto assim....

gostaria de pronunciar que: ´Já estou envolvida! Se o Jú pular... tb pulo!´ (plagiei do Leo di Caprio em Titanic).


Vamos torcer para que o Ju Pule, assim estaremos preparados para te salvar.. Quanto ao ju :?: :?: :?: Quem mandou ele pular. Fazer o que né

Só pra descontarir tá!?



GOSTEI 0
Massuda

Massuda

08/06/2005

...A não ser pelo fato de que ao abrir vários forms filhos e depois mandar organizar a janela com os comandos: Cascade, tilemode:=tbhorizontal, tilemode:=tbvertical e arrangeicons, os forms minimizam ficando parcialmente visíveis, mas sem poder aumentar o tamanho deles e nem manipulá-los como se tivessem sido organizados pelo excell por exemplo.
Não sei se entendi direito seu porém, mas numa aplicação MDI, os forms com estilo fsMDIChild viram ´ícones´ dentro do form principal (com estilo fsMDIForm) quando são minimizados.


GOSTEI 0
Michelle

Michelle

08/06/2005

[quote:dcb913f3d3=´Michelle´]...A não ser pelo fato de que ao abrir vários forms filhos e depois mandar organizar a janela com os comandos: Cascade, tilemode:=tbhorizontal, tilemode:=tbvertical e arrangeicons, os forms minimizam ficando parcialmente visíveis, mas sem poder aumentar o tamanho deles e nem manipulá-los como se tivessem sido organizados pelo excell por exemplo.
Não sei se entendi direito seu porém, mas numa aplicação MDI, os forms com estilo fsMDIChild viram ´ícones´ dentro do form principal (com estilo fsMDIForm) quando são minimizados.[/quote:dcb913f3d3]

Mudei algumas propriedades dos meus forms Filhos e deu certo:

BorderStyle=bsSizeable
Position=poMainFormCenter
PrintScale=poProportional
WindowState=wsMaximized

Valeu a atenção!


GOSTEI 0
Powerlog Tecnologia

Powerlog Tecnologia

08/06/2005

Pessoal, tentei fazer um ´merge´ da função abre form com o que foi dito aqui. Porém meu form filho só PISCA e não fica visível.

procedure AbreForm(FormClasse: TComponentClass; NomeForm:TForm);
begin
  Application.Createform(FormClasse, NomeForm);
  NomeForm.FormStyle := fsMDIChild;
  NomeForm.BorderStyle := bsSizeable;
  NomeForm.Position := poMainFormCenter;
  NomeForm.PrintScale := poProportional;
  NomeForm.WindowState := wsMaximized;
  NomeForm.Visible := true;
  try
    NomeForm.Show;
  finally
    NomeForm.Free;
  end;
end;


Alguma dica?

:?:


GOSTEI 0
Paullsoftware

Paullsoftware

08/06/2005

Amigo, eu trabalho com MidForms a algum tempo e sempre usei o seguinte código, comigo funciona perfeitamente...


Esta função serve para verificar se o form já está criado...
function ChecaForm(aForm: Tform): Boolean;
var
I:Integer;
begin
    ChecaForm := false;
    for I := 0 to Screen.FormCount -1 do
    if Screen.Forms[i] = aForm then
    begin
    ChecaForm := true;
    Break;
    end;
end;  (* ChecaForm *)

e para chamar o mesmo faço assim:
   
if ChecaForm(FrmExibeRecados) then
    begin
      FrmExibeRecados.BringToFront;
      FrmExibeRecados.Focused;
    end
   else
    begin
      FrmExibeRecados := TFrmExibeRecados.Create(nil);
      FrmExibeRecados.BringToFront;
      FrmExibeRecados.Focused;
    end;
  end;


Obs.:
para que você possa usar esse metodo algumas configurações básicas são necessárias...
o seu Form Principal tem que tá com a propriedade Form [b:ccec5360f6]Estyle = fsMDIForm[/b:ccec5360f6] e seus forms filhos deve está com essa mesma propriedade setada para [b:ccec5360f6]fsMDIChild[/b:ccec5360f6] no evento OnClose dos seus forms filhos você deve colocar o código:
 Action := CaFree;

pronto! apenas isso é necessário, espero ter ajudado!!! :wink:


GOSTEI 0
Powerlog Tecnologia

Powerlog Tecnologia

08/06/2005

Colocando no form principal, dá certo. Agora seu eu quero colocar na função ´AbreForm´, dá erro

  NomeForm := FormClasse.create(nil); 


Incompatible types: TForm and TComponent

De qualquer forma farei a chamada no form principal para resolver o meu problema de abrir várias telas (MDI).

Valeu !!!!!!!!!!!!!!!!!!!!!!!!!!!!


GOSTEI 0
Powerlog Tecnologia

Powerlog Tecnologia

08/06/2005

Só pra encerrar (da minha parte), como por função não vai, todas as chamadas ficaram assim:

  
  if not ChecaForm(fmMtFornec) then
    fmMtFornec := TFmMtFornec.create(nil);
  fmMtFornec.BringToFront;
  fmMtFornec.Focused;


Obrigado pela dica


GOSTEI 0
POSTAR