IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Composants VCL Delphi Discussion :

Comment n'avoir qu'une seule instance d'une fenêtre fille dans une application MDI ?


Sujet :

Composants VCL Delphi

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Décembre 2002
    Messages : 32
    Points : 23
    Points
    23
    Par défaut Comment n'avoir qu'une seule instance d'une fenêtre fille dans une application MDI ?
    Bonjour,

    Comment fait-on pour créer une seule instance d'une fenetre fille dans une application MDI.
    Ce que j'aimerais c'est empecher l'ouverture de deux modules identiques lorsque l'utilisateur clique deux fois sur la meme option.
    En fait j'aimerais amener en avant plan le module déjà ouvert.

    Merci de votre aide

    J'utilise D7 Ent
    "Selon que notre idée est plus ou moins obscure
    L'expression la suit ou moins nette ou plus pure..."

  2. #2
    Membre confirmé Avatar de JustMe
    Inscrit en
    Juillet 2002
    Messages
    479
    Détails du profil
    Informations forums :
    Inscription : Juillet 2002
    Messages : 479
    Points : 593
    Points
    593
    Par défaut
    Tu test à la création si ta forme pointe quelque part
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    if FicheFille = Nil then 
    // Tu la crée
    Mais à sa fermeture OnClose tu met
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FreeAndNil(FicheFille);
    <On fait la science avec des faits, comme on fait une maison avec des pierres : mais une accumulation de faits n'est pas plus une science qu'un tas de pierres n'est une maison> **Poincaré**

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Décembre 2002
    Messages : 32
    Points : 23
    Points
    23
    Par défaut
    La première fois la variable Feuille fille pointe forcément nulle part. Donc la feuille fille ne s'affiche jamais...

    Voici le code qui crée la f fille
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    procedure TMainFormPro.CreateFrmFeuilleFille(const Name: string);
    var
      Formulaire: TFrmFeuilleFille;
    begin
           Formulaire := TFrmFeuilleFille.Create(Application);
           Formulaire.Caption := Name;
           Formulaire.pnlTitreFenetre.Caption := Name;
    end;
    "Selon que notre idée est plus ou moins obscure
    L'expression la suit ou moins nette ou plus pure..."

  4. #4
    Membre averti
    Avatar de Hauwke
    Inscrit en
    Septembre 2005
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 329
    Points : 400
    Points
    400
    Par défaut
    Bonjour,
    Citation Envoyé par kolac
    La première fois la variable Feuille fille pointe forcément nulle part. Donc la feuille fille ne s'affiche jamais...
    Forcément, si tu la crées pas...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TMainFormPro.CreateFrmFeuilleFille(const Name: string); 
    var 
      Formulaire: TFrmFeuilleFille; 
    begin
           if Formulaire = Nil then
           begin  
           Formulaire := TFrmFeuilleFille.Create(Application); 
           Formulaire.Caption := Name; 
           Formulaire.pnlTitreFenetre.Caption := Name;
           end else
           Formulaire.bringtofront; 
    end;
    Ne pas oublier de suivre la fin du post de JustMe avec le OnClose
    Cordialement,
    Hauwke

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Décembre 2002
    Messages : 32
    Points : 23
    Points
    23
    Par défaut
    Bonjour Hauwke,

    La procedure CreateFrmFeuilleFille s'execute sur clic d'un bouton de la barre d'outils ou du menu "Gestion".
    La premiere fois ca va bien, mais si l'utilisateur clique sur la meme option une seconde fois, une seconde instance de FeuilleFille est à noiuveau créée car Formulaire est toujours Nil à chaque nouvelle exécution de la procécure et c'est ce que je voudrais éviter...
    Peut-on faire autrement ?

    Merci d'avance...
    "Selon que notre idée est plus ou moins obscure
    L'expression la suit ou moins nette ou plus pure..."

  6. #6
    Membre averti
    Avatar de Hauwke
    Inscrit en
    Septembre 2005
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 329
    Points : 400
    Points
    400
    Par défaut
    Bonjour,
    Je pense que tu peux essayer celà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    var
    i,j:integer;
    Formulaire: TFrmFeuilleFille;
    begin
    For i:=0 to application.componentcount-1 do// On recense ts les compo de l'appli (les conteneurs ds ton cas)
    for j:=0 to application.components[i].componentcount-1 do // tous les compo contenus
    begin
    if (Application.components[i]components[j].classtype=TfrmFeuilleFille) then // si y'en a au moins un qui existe de ton type on l'amméne au premier plan
    Application.components[i].components[j].bringtofront else // sinon on le crée
    begin  
           Formulaire := TFrmFeuilleFille.Create(Application); 
           Formulaire.Caption := Name; 
           Formulaire.pnlTitreFenetre.Caption := Name; 
           end; 
         end;
    end;
    J'ai pas testé, mais l'esprit y est...
    Cordialement,
    hauwke
    [edit] Ca va pas marcher, je pense! à la relecture de mon post, il faut finir le test des composants avant de rentrer dans la section de création! Sinon il va créer une fenêtre à chaque fois qu'un compo ne sera pas du bon type! Mais tu as la base de travail[/edit]

  7. #7
    Membre averti
    Avatar de Hauwke
    Inscrit en
    Septembre 2005
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 329
    Points : 400
    Points
    400
    Par défaut
    Re bonjour,
    je crois que le plus simple serait de créer un compteur global et de le lire avant de faire quoi que se soit, du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    procedure TMainFormPro.CreateFrmFeuilleFille(const Name: string); 
    var 
      Formulaire: TFrmFeuilleFille;
      Comp:integer;// Je mets la variable ici mais il serait bon d'en faire une var globale pour pouvoir initialiser et tester au début de l'appli
    // et surtout pouvoir s'en resservir ailleurs que dans ton bouton ;) 
    begin 
           if comp<>1 then 
           begin  
           Formulaire := TFrmFeuilleFille.Create(Application);
           comp:=(comp+1); 
           Formulaire.Caption := Name; 
           Formulaire.pnlTitreFenetre.Caption := Name; 
           end else 
           Formulaire.bringtofront; 
    end;
    il te faudra initialiser ton compteur (comp:=0) à l'initialisation de ton appli. c'est pas trés beau comme code mais ça doit marcher
    Cordialement,
    Hauwke

  8. #8
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    procedure TMainFormPro.CreateFrmFeuilleFille(const Name: string);
    var
      Formulaire: TFrmFeuilleFille;
    begin
      if FindComponent('MAFILLE') = nil then
      begin
         Formulaire := TFrmFeuilleFille.Create(Application);
         Formulaire.Caption := Name;
         Formulaire.pnlTitreFenetre.Caption := Name;
         Formulaire.Name := 'MAFILLE';
      end else
        TFrmFeuilleFille(FindComponent('MAFILLE')).show;
    end;
    En gros comme ça ca devrait fonctionner
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Décembre 2002
    Messages
    32
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations forums :
    Inscription : Décembre 2002
    Messages : 32
    Points : 23
    Points
    23
    Par défaut
    Bonjour,

    Non, ca ne fonctionne toujours pas. FindComponent retourne toujours vrai et il crée au second clic, une nouvelle instance de FeuilleFille. Mais ce que j'ai noté c'est que la premiere instance s'appelle FeuilleFille, la seconde FeuilleFille_1, la troisieme FeuilleFille_2 etc. Ce qui explique le test FindComponent(...) = Nil est toujours vrai.
    En ce qui concerne la méthode de Hauwke, j'ai 9 modules dans mon application ce qui reviendrait si j'ai bien compris à créer 9 variables globales. Je ne suis pas familier avec l'utilisation des variables globales...

    Comment peut on arriver à bout de mon pb ???

    Merci
    "Selon que notre idée est plus ou moins obscure
    L'expression la suit ou moins nette ou plus pure..."

  10. #10
    Membre averti
    Avatar de Hauwke
    Inscrit en
    Septembre 2005
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 329
    Points : 400
    Points
    400
    Par défaut
    Bonsoir,
    Je ne suis pas assez calé en théorie pour expliquer clairement toutes les finesses de l'utilisation d'une variable globale. Je vais donc le faire partiellement, en demandant aux experts du forum de bien vouloir compléter la définition... D'avance merci à eux.

    En fait lorsque tu crées une variable dans ta méthode (procédure ou fonction) elle n'est accéssible que dans cette méthode. Si tu la déclares dans la partie implémentation elle sera visible, donc accessible, à toutes les méthodes de cette unité et ainsi de suite en remontant. Plus tu la déclares haut dans ton application et plus tu étends son champ de visibilité, d'accessibilité, aux autres participants de ton application.
    Dans ton cas, la bonne granulométrie doit être l'unité du projet. En déclarant ta variable "comp:integer" dans la partie interface tu vas rendre ce compteur visible pour tes neufs modules.(j'ai supposé qu'il s'agissait de 9 unités distinctes)
    J'avais déjà eu afffaire avec "findcomponent()".
    Le point commun de toutes tes fenêtres filles, quelque soit leur nom, est leur type! Elles sont toutes des instances de ta classe "TFrmFeuilleFille".
    Au démarrage de ton soft, il te faut initialiser "comp:=0;"avant toute création de fenêtre fille et l'incrémenter de "1" à la création de cette façon tu n'as plus besoin de vérifier la classe mais seulement de tester la valeur de ton compteur. Si sa valeur est différente de "0" c'est que quelque part tu as une fenêtre fille qui est instanciée dans les autres cas comp<1 tu dois la créer, comp>1 alors là il y a un os dans ton algo, tu as plus d'une fenêtre de ce type "vivante" à l'instant du test. Attention, cependant, le fait que le comp>1 soit vrai ne signifie pas que ton soft vive avec deux fenêtres! Je ne saurai pas expliquer la théorie mais il semblerait que la destruction des objets ne soit pas aussi instantanée que nous le souhaiterions. Il y a un délai de latence qui n'interrompt pas l'éxécution du code! De fait, ton compteur peut, momentanément, dépasser la valeur "1" mais ne pourra jamais dépassé la valeur "2" (dans ton cas). -Déclaration basée sur une expérience empirique de tests de comsommation mémoire-
    Voilà, pour ce que je sais de la théorie de la visibilité des variables dans une application avec Delphi. J'espére n'avoir pas été trop brouillon dans mes explications. Pour le code, je m'y mets dés demain matin...
    Cordialement,
    Hauwke

  11. #11
    Membre averti
    Avatar de Hauwke
    Inscrit en
    Septembre 2005
    Messages
    329
    Détails du profil
    Informations forums :
    Inscription : Septembre 2005
    Messages : 329
    Points : 400
    Points
    400
    Par défaut
    Bonjour,
    Comme promis hier soir:
    Le code du projet:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    program Project1;
     
    uses
      Forms,
      Unit1 in 'Unit1.pas' {Form1},
      Unit2 in 'Unit2.pas' {Form2};
     
    {$R *.res}
     
    begin
      Application.Initialize;
      compteurdefille:=0; // Compteur à 0 à l'entrée du programme
      Application.CreateForm(TForm1, Form1);
      Application.Run;
    end.
    Le code de la fenêtre mère:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    unit Unit1;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls;
    Var
    Compteurdefille:integer;
    type
      TForm1 = class(TForm)
        Panel1: TPanel;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    uses Unit2;
     
    {$R *.dfm}
     
    procedure TForm1.Button1Click(Sender: TObject);
    Var
    From2:Tform2;
    begin
    If compteurdefille=0 then               // on teste le compteur
    begin
    Form2:=Tform2.Create(Application);      // Il vaut 0 donc on crée la fille
    Compteurdefille:=(compteurdefille+1);   // on incrémente le compteur
    // on fait ce que l'on a faire avec la fille avant affichage
    end
    else // le compteur vaut au moins 1 on active la fille
    Form2.bringtofront;  // Celà ne marche pas avec une fille minimiser
    // ni form2.show!
    //Il faut utiliser l'API pour restaurer la fille dans l'écran
    // Je cherche la fonction correspondante et j'update le code
    // Mais le reste fonctionne
    end;
     
    end.
    Le code de la fille:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    unit Unit2;
     
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
     
    type
      TForm2 = class(TForm)
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form2: TForm2;
     
    implementation
     
    uses Unit1;
     
    {$R *.dfm}
     
    procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
    FreeandNil(form2);/: On libére tout à la fermeture de la fille
    Compteurdefille:=(compteurdefille-1);/: on décrémente le compteur
    end;
     
    end.
    Le code fonctionne chez moi, aprés création de la première fille il est impossible d'en créer une seconde. En fermant la fille et en appuyant sur le bouton de la fenêtre 1 on recrée la première fille. le compteur d'instance n'est pas incrémenté. (form2_1; form2_2...) mais reste bien à "form2". Il ne me reste plus qu'a trouver l'API pour restaurer la fille lorsqu'elle est minimisée et je pense que l'on aura résolu ton problème, non?
    Cordialement,
    Hauwke

  12. #12
    Modérateur
    Avatar de Rayek
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2005
    Messages
    5 235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 5 235
    Points : 8 504
    Points
    8 504
    Par défaut
    Citation Envoyé par kolac
    Bonjour,

    Non, ca ne fonctionne toujours pas. FindComponent retourne toujours vrai et il crée au second clic, une nouvelle instance de FeuilleFille. Mais ce que j'ai noté c'est que la premiere instance s'appelle FeuilleFille, la seconde FeuilleFille_1, la troisieme FeuilleFille_2 etc. Ce qui explique le test FindComponent(...) = Nil est toujours vrai.
    En ce qui concerne la méthode de Hauwke, j'ai 9 modules dans mon application ce qui reviendrait si j'ai bien compris à créer 9 variables globales. Je ne suis pas familier avec l'utilisation des variables globales...

    Comment peut on arriver à bout de mon pb ???

    Merci
    Ca fonctionne parfaitement chez moi avec la méthode que je t'ai fourni.
    J'ai juste oublié une chose au niveau du else :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TFrmFeuilleFille(FindComponent('MAFILLE')).WindowState := wsMaximized; // ou wsNormal selon les besoins
    j'ai noté c'est que la premiere instance s'appelle FeuilleFille, la seconde FeuilleFille_1, la troisieme FeuilleFille_2 etc. Ce qui explique le test FindComponent(...) = Nil est toujours vrai.
    tu aurais pas oublier de nommer la feuille comme je te l'indique dans mon code ? Car si tu as les instances comme tu les decrit, c'est que tu renommes pas la form.
    Modérateur Delphi

    Le guide du bon forumeur :
    __________
    Rayek World : Youtube Facebook

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [WD14] Plusieurs fenêtres internes dans une seule fenêtre (mère)
    Par luludev dans le forum WinDev
    Réponses: 6
    Dernier message: 02/08/2012, 14h16
  2. Réponses: 1
    Dernier message: 21/12/2007, 21h27
  3. Réponses: 3
    Dernier message: 30/04/2007, 12h22
  4. Une seule instance de l'appli et exécuter une procédure
    Par Manic dans le forum API, COM et SDKs
    Réponses: 11
    Dernier message: 08/03/2006, 11h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo