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

Langage Delphi Discussion :

[FRAME] : procédure générique de chargement


Sujet :

Langage Delphi

  1. #1
    Membre averti
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Points : 436
    Points
    436
    Par défaut [FRAME] : procédure générique de chargement
    Bonjour,

    Je reprends la maintenance d’une appli qui commence sérieux à me faire ……..bip LOL
    Je rencontre de grosses difficultés pour rendre générique une procédure d’affichage de frames.

    Je m’explique en détails (scuzzy pour la tartine )
    J’ai une application composée d’une fenêtre Principal qui charge des frames dans un conteneur TPanel.
    Mes frames héritent de plusieurs frames maisons. J’ai en tout une bonne cinquantaine de frames.

    Pour expliquer mon problème j’ai simplifié tout çà pour vous l’exposer : j’ai une classe TFrmModele qui hérite de TFrame.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
    TFrmModele = class(TFrame)
        PanelTitre: TPanel;
        Panel1: TPanel;
        BtnFermer: TButton;
        procedure BtnFermerClick(Sender: TObject);
    public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        procedure Afficher; virtual;
        procedure Fermer;
    end;
    Je crée ensuite plusieurs frames filles qui héritent de TFrmModele : FrEcran1, FrEcran2, FrEcran3
    Chaque fenetre fille surcharge la procédure Afficher pour permettre la personnalisation de la Frame.
    Rien d’exceptionnel.

    Pour charger mes frames actuellement, j’ai cette simple procédure au niveau de la form Principal :

    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
    Var (public)
    MyFrame :TFrmModele ;
     
    implementation
     
    uses FrEcran1, FrEcran2, FrEcran3;
     
    procedure TFPrincipal.AfficherEcran(PMyEcran:string;PConteneur:TPanel);
    begin
      try
        FreeAndNil(MyFrame);
        if PMyEcran='FrEcran1' then MyFrame := TFrmEcran1.Create(self)
        else if PMyEcran='FrEcran2' then MyFrame := TFrmEcran2.Create(self)
        else if PMyEcran='FrEcran3' then MyFrame := TFrmEcran3.Create(self)
        else exit;
         MyFrame.Parent := PConteneur;
         MyFrame.Afficher;
      except
        on E: Exception do MessageDlg('Contacter l''administrateur :'#13#10+E.Message,mtError,[mbOk],0);
      end;
    end;
    Pour tester ma procédure, j’ai simplement mis en place une procédure OnClick à partir de ma form Principal, que je teste avec plusieurs TButton

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //------------------------------------------------------------------------------
    procedure TFPrincipal.MenuClick(Sender: TObject);
    begin
    	if      Sender = Button1 then AfficherEcran('FrEcran1',self.PanelFrame)
    	else if Sender = Button2 then AfficherEcran('FrEcran2', self.PanelFrame)
    	else if Sender = Button3 then AfficherEcran('FrEcran3', self.PanelFrame)
    	else if Sender = Button4 then AfficherEcran('FrEcran4', self.PanelFrame)
    	else Exit;
    end;
    Jusque là c’est pas tip top, mais çà marche.
    Le pb que je dois résoudre désormais est que mes frames doivent pouvoir s’appeler les unes les autres, et cela avec une seule procédure AfficherEcran

    Je dois par exemple demander à partir de ma frame FrEcran1, l’ouverture de la frame FrEcran 2 et vice versa. Cela je souhaiterai réussir à la faire en appelant uniquement la procédure de ma forme principale (que je souhaiterai ensuite gérer dans une class TMyGesFrames)

    J’ai donc repris le code ci-dessus, en m’orientant sur une TList qui se chargerait de stocker des types records

    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
    type
      PMyFrame=^TMyFrame;
      TMyFrame=record
        MyFrameName:string;
        MyFrame:TFrmModele;
    end;
     
    //Nouvelle procédure AfficherEcran
    //------------------------------------------------------------------------------
    procedure TFPrincipal.AfficherMyEcran(PMyEcran:string;PConteneur:TPanel);
    var
      PMyFrameModel:PMyFrame;
      PList:integer;
      Find:boolean;
      ClassRef:TClass;
    begin
      try
        Find:=false;
        //--FIND INSTANCE STOCKEE : function GetFrame à faire
        for PList:=0 to FMyListFrames.Count-1 do
          begin
            PMyFrameModel:=FMyListFrames.Items[PList];
            if PMyFrameModel^.MyFrameName=PMyEcran then
              begin
                ShowMessage('ON A RETROUVE '+PMyEcran+' instance de classe '+PMyFrameModel^.MyFrame.ClassName);
                Find:=true;
                exit;
              end;
          end;
        if not(Find) then
          begin
            new(PMyFrameModel);
            if PMyEcran='FrEcran1' then PMyFrameModel^.MyFrame := TFrmEcran1.Create(FPrincipal)
            else if PMyEcran='FrEcran2' then PMyFrameModel^.MyFrame := TFrmEcran2.Create(FPrincipal)
            else if PMyEcran='FrEcran3' then PMyFrameModel^.MyFrame := TFrmEcran3.Create(FPrincipal)
            else if PMyEcran='FrEcran4' then PMyFrameModel^.MyFrame := TFrmEcran4.Create(FPrincipal)
            else exit;
            PMyFrameModel^.MyFrameName:=PMyEcran;
            FMyListFrames.Add(PMyFrameModel);
            ClassRef:=PMyFrameModel^.MyFrame.ClassType;
            Showmessage('on a ajouté '+PMyEcran+' à la TList maison de classe '+ClassRef.ClassName);
          end;
        PMyFrameModel^.MyFrame.Parent := PConteneur;
        PMyFrameModel^.MyFrame.Afficher;
      except
        on E: Exception do MessageDlg('Contacter l''administrateur :'#13#10+E.Message,mtError,[mbOk],0);
      end;
    end;
    Ce que je cherche à faire, c’est parcourir ma Tlist à chaque demande de chargement d’une frame.
    S’il ne la retrouve pas il créé une nouvelle instance fille, en fonction du nom de l'écran passé en paramétre
    S’il la trouve, je voudrai pouvoir l’utiliser pour appeler de nouveau la procédure surchargée ‘Appeler’.

    * la création des nouvelles instances et le stockage dans la Tlist : ok çà fonctionne, la procédure Afficher lorsque je créé une nouvelle instance : ok çà fonctionne
    * il retrouve bien mon instance fille une fois crée, la classe Référence de ma frame (ici dans le source ClassRef), mais l’appel de ma procédure Afficher ne marche pas, j’ai essayé en vain :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    PMyFrameModel^.MyFrame.Afficher;
    TFrmModele(PMyFrameModel^.MyFrame as ClassRef).Afficher;
    //pour tester récupération instance CAST
    if PMyEcran='FrEcran1' then (PMyFrameModel^.MyFrame as TFrmEcran1).Afficher..
    Je pense que pour que cela fonctionne il faut que j’arrive à un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    (PMyFrameModel^.MyFrame as ClassRef).Afficher
    Mais je n’y arrive pas !

    L’appel pour l’instant de ma procédure AfficherEcran depuis une frame chargée, me génére une violation d’accés.

    Exemple d’appel depuis ma frame FrEcran1 (Evt OnClick par exemple):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    implementation
     
    uses Principal;
     
    procedure TFrmEcran1.Button1Click(Sender: TObject);
    begin
     FPrincipal.AfficherMyEcran('FrEcran2',FPrincipal.PanelFrame);
    end ;
    Quid de ce qui ne và pas docteur ?
    1/ dans la gestion de ma Tlist pour récupérer une instance et pouvoir appeler la procédure surchargée ‘Appeler’
    2/ dans l’appel de ma procédure Fprincipal.AfficherEcran depuis une frame ?
    3/ si cela n’est pas abusé, j’aimerai également trouver une solution pour la création d’une instance et éviter de devoir faire :
    if PMyEcran='FrEcran1' then PMyFrameModel^.MyFrame := TFrmEcran1.Create(FPrincipal)
    else if PMyEcran='FrEcran2' then PMyFrameModel^.MyFrame := TFrmEcran2.Create(FPrincipal)
    else if .......
    j’ai une cinquantaire d’écrans c’est pas tip top. Comment peut-on rendre cela complémentement générique+Eviter dans les uses de ma feuille principal d’avoir mes 50 frames à implémenter ? RegisterClass ?

    Merci d’avance aux courageux ki voudront bien m’aider en cette période estivale .

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Une TStringList aurait été plus simple pour gérer des Objets, avec les propriétés Strings et Objects, qui en plus fourni une méthode IndexOf ...

    Ensuite, pourquoi ne pas utiliser le nom de la classe (TFrmEcran1.ClassName) ou directement avec la Référence de Classe ... (voir class of et ClassType), en plus tu avais commencé à y toucher ...

    Sinon, Tu aurais pu passer par un Owner commun qui contiendrait ses Frames dans sa propriété Compoents ...

    Enfin, remplace le Exit par un Break, ...

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    42
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 42
    Points : 51
    Points
    51
    Par défaut
    bonjour,

    j'utilise un procédé un peu similaire,
    je procède ainsi

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    type
     
      PMyFrame=^TMyFrame;
     
      TFrmModeleClass = class of TFrmModele;
     
      TMyFrame=record
        MyFrameName:string;  // <- ShaiLeTroll a raison il vaut mieux 
                                       // utiliser le classname ici
        MyFrame:TFrmModeleClass;
    end;
    normalement le type TFrmModeleClass accepte tous les descendants de TFrmModele

    du coup, pour créer la bonne instance de frame,
    une fois le bon record localisé grace au classname,
    il n'y a plus qu'a utiliser MyFrame.create(...)

  4. #4
    Membre averti
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Points : 436
    Points
    436
    Par défaut
    Merci à vous 2 pour votre participation

    est-il possible sans vouloir abuser d'avoir un exemple de gestion avec une TStringList ?
    je commence à avoir la tete à l'envers à force de me prendre la tete sur ce pb, vivement les vacances

  5. #5
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Disons que la TStringList ou TObjetList, ça donne globalement pareil (sauf le Add et OwnObjects)

    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
    type
      TFrmModeleClass = class of TFrmModele;
     
    procedure TFPrincipal.AfficherMyEcran(AFrameClass: TFrmModeleClass; AParent: TPanel);
    var
      I: Integer;
      Find: Boolean;
      FrameInstance: TFrmModele;
    begin
      try
        Find := False;
        // Cherche une instance déjà existante
        for I := 0 to FObjectListFrames.Count-1 do // TStringList c'est Objects, et TObjectlist c'est Items
        begin
          FrameInstance := FObjectListFrames.Objects[I] as TFrmModele; // On suppose que FObjectListFrames ne contient QUE ça, sinon fait un "is" avant
          if FrameInstance.ClassType = AFrameClass then
            begin
              Find := True;
              Break;
            end;
        end;      
     
        if not Find then
        begin
          FrameInstance := AFrameClass.Create(FPrincipal);
          FObjectListFrames.Add(FrameInstance.Name, FrameInstance); // je prend le nom de l'instance, il est normalement unique et fourni par delphi à la création de l'objet, à vérifier
        end;
     
        FrameInstance.Parent := AParent;
        FrameInstance.Afficher();
      except
        on E: Exception do MessageDlg('Contacter l''administrateur :'#13#10+E.Message,mtError,[mbOk],0);
      end;
    end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TFrmEcran1.Button1Click(Sender: TObject);
    begin
     FPrincipal.AfficherMyEcran(TFrmEcran2, FPrincipal.PanelFrame);
    end ;

  6. #6
    Membre averti
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Points : 436
    Points
    436
    Par défaut
    Tout d'abord merci infiniment à toi ShaiLeTroll pour ta patience et le tps que tu as passé à me fournir cet exemple.

    J'ai repris celui-ci
    j'ai modifié :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    FObjectListFrames.Add(FrameInstance.Name, FrameInstance);
    par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FObjectListFrames.AddObject(FrameInstance.Name, FrameInstance);
    - l'ajout dans la TStringList des nouvelles instances fonctionnent très bien
    ielles appellent correctement la procédure Afficher de mes classes filles;

    - il retrouve correctement l'instance une fois celle-ci créée. j'ai débuggé il passe bien également par la procédure Afficher de mes classes filles, par contre le conteneur TPanel ne se rafraichit pas, il reste sur l'ancien objet frame chargé.
    j'ai essayé des refresh, repaint, rien à faire.

    Tu as une idée d'où peut venir le pb? merci encore

  7. #7
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 612
    Points : 25 303
    Points
    25 303
    Par défaut
    Essaye un BringToFront dans le Afficher, sinon, avant d'appeler, cache toutes les frames déjà chargées ...

    Une application MDI n'aurait pas été plus simple ?

  8. #8
    Membre averti
    Inscrit en
    Novembre 2002
    Messages
    549
    Détails du profil
    Informations forums :
    Inscription : Novembre 2002
    Messages : 549
    Points : 436
    Points
    436
    Par défaut
    Avec BringToFront, que j'ai mis dans la procédure Appeler de la classe mére, çà fonctionne impec'.



    t'es THE KING !!!!!!!

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

Discussions similaires

  1. [MySQL-5.5] Procédure Stockée MySQL à chargement infini
    Par jams971 dans le forum SQL Procédural
    Réponses: 0
    Dernier message: 14/08/2013, 13h18
  2. [11gR2] Procédure générique pour insérer des valeurs dans une table
    Par bibi_obs dans le forum PL/SQL
    Réponses: 7
    Dernier message: 29/03/2013, 11h18
  3. [VB.NET]procédure générique d'initialisation
    Par Kropernic dans le forum Windows Forms
    Réponses: 2
    Dernier message: 18/03/2007, 15h36
  4. [VBA-E] Procédure utilisée au chargement de chaque feuille
    Par sat478 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 28/04/2006, 16h46
  5. Surcharge d'une procédure dans l'instance d'une frame
    Par damien.yep dans le forum Composants VCL
    Réponses: 3
    Dernier message: 14/09/2005, 15h28

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