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

Lazarus Pascal Discussion :

Indirection sur des TForms et appel de procédures


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Invité
    Invité(e)
    Par défaut Indirection sur des TForms et appel de procédures
    Bonjour,

    je n'arrive pas à créer - mais je ne sais pas si c'est possible dans ce cas - une indirection sur les TForms permettant d'utiliser des procedures contenues dans ces dernières.

    J'ai 2 Forms, Form1 et Form2 qui contiennent chacune une procedure disons ProcHomonyme() définie ainsi
    * procedure TForm1.ProcHomonyme(Sender: TObject); //dans l'unit1;
    * procedure TForm2.ProcHomonyme(Sender: TObject); //dans l'unit2;
    Evidemment bien qu'elles soient homonymes, elles ont des contenus différents. Elles sont appelées lors de la création de chacune des Forms 1 et 2 et ces 2 procédures sont également appelées par une autre Form, TFormMain, ainsi :

    uses ...., unit1, unit2;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var
        i : integer;
    begin
      for i := 0 to Screen.FormCount-1 do
        // uses StrUtils;
        case AnsiIndexStr(Screen.Forms[i].UnitName, ['unit1', 'unit2']) of
             0 : Form1.ProcHomonyme(nil);
             1 : Form2.ProcHomonyme(nil);
          //-1 : Aucun cas
        end;
    end;
    Cela fonctionne.


    Je me suis demandé si je pouvais faire une indirection sur une TForm avec Lazarus. C'est peut-être un peu osé voire même complètement idiot dans ce cas [appel d'une procédure] ?

    Donc, toujours dans TFormMain :

    type
    P = ^TForm;

    et dans la procédure d'appel
    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
    var
        i : integer;
        F : P;
    begin
      for i := 0 to Screen.FormCount-1 do 
        begin
          new(F);
          F^ := screen.Forms[i];
          F^.Caption := 'Truc '+ IntToStr(i);  //Fonctionne bien. Le caption des 
          //Forms est bien changé.
          //Par contre 
          //F^.Name.ProcHomonyme(nil); :oops:
          // Peut-on appeler les fonctions ProcHomonyme(nil) ?
          // Si oui, comment ?
          // Faut-il les déclarer d'une manière spécifique dans les Forms 1 et 2 
          // (surchargées) pour qu'elles soient appelables avec cette méthode ? 
          dispose(F);
        end;
    end;
    Merci. Cordialement.
    Gilles
    Dernière modification par Invité ; 07/07/2010 à 14h30. Motif: Précisions

  2. #2
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Par défaut
    Citation Envoyé par selzig Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
          //F^.Name.ProcHomonyme(nil); :oops:
          // Peut-on appeler les fonctions ProcHomonyme(nil) ?
          // Si oui, comment ?
          // Faut-il les déclarer d'une manière spécifique dans les Forms 1 et 2 
          // (surchargées) pour qu'elles soient appelables avec cette méthode ? 
          dispose(F);
        end;
    end;
    F^.Name retourne une valeur de type TComponentName qui en fait est une chaîne. Et comme une chaîne n'est pas un type objet et n'a donc pas de méthode ProcHomonyme cela ne peut effectivement pas marcher.

    Je ne suis pas certain de bien comprendre ce que tu veux faire mais je vais essayer.

    Je crois comprendre que ton but est de créer une méthode ProcHomonyme pour différentes fenêtres (TForm) définies dans différentes unités puis de créer un tableau de ces fenêtres et d'appeler la méthode ProcHomonyme pour chaque élément du tableau. C'est bien ça ?

  3. #3
    Invité
    Invité(e)
    Par défaut
    En effet, pour être clair,

    J'utilise un sdi maison et je gère les fenêtres ouvertes... à partir de uMain. Donc, en fonction du bouton sélectionné, toutes les fenêtres se réduisent ou se mettent en cascade,... ou depuis peu, on change de langue (pour les captions, title & co).

    J'ai déjà une solution rudimentaire avec mon case Of mais pour me faire plaisir, j'avais envie de voir ce que je valais en class derivée, méthode surchargée... Ben, c'est plus trop brillant... Enfin c'est ce qu'on voudrait pouvoir se dire. On sublime toujours le passé. Bon, ce n'est PAS brillant.

    J'ai donc créé une class dérivée de Tform (*pour tester, j'ai pris procShow à la place de ProcHomonyme...) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    type   
    TFormHomonyme = Class(TForm)
        private
          { private declarations }
        public
          { public declarations }
         Procedure procShow(Sender : TObject, sMess : string);
        end;
    Et c'est là qu'après, je ne suis plus...

    J'arrive bien à déclencher la ProcHomonyme dans une TForm1 par exemple, mais pas dans TForm2. Et d'un autre côté, cette ProcHomonyme doit également exister dans TFormMain... J'ai quelques bouts de code qui fonctionnent avec des TFormHomonyme(Tform1).ProcHomonyme(nil); Mais rien qui fonctionne globalement et dans les 3 fenêtres en même temps.

    Avec quelque chose du genre [dans un bouton de TformMain]
    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 TFormMain.Button1Click(Sender: TObject);
    //Bouton de Test
    begin    
     TFormHomonyme(FormMain).TFormHomonyme(FormMain).procShow(nil,'en local');  
    {la ligne du dessus paraît idiote (puisque je suis dans TFormMain, 
    mais je ne veux pas différencier le code dans la boucle qui parcourt 
    les screen.Form[x]. 
    Que ce soit uMain ou unit1 et unit2 appelées par uMain, 
    la procédure d'appel de la fonction prosShow doit être identique.}
     Application.CreateForm(TForm1, Form1);
     Form1.Show;TFormHomonyme(Form1).procShow(nil,'en appel');   
     Application.CreateForm(TForm2, Form2);
     Form2.Show;TFormHomonyme(Form2).procShow(nil,'en appel');  
    end;
    en simplifiant au départ dans FormMain,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Procedure TFormHomonyme.procShow(Sender: TObject;sMess:string);
    begin
      FormMain.label1.caption:= smess;
    end;
    Je suis arrivé à quelques choses de plus satisfaisant en appelant les fonctions
    procShowMain, procShowForm1, ProcShowForm2 toujours avec des TFormHomonyme mais cela s'emboite mal dans le reste du code et c'est peu satisfaisant. Ce n'est pas ce que je cherchais.

    J'ai vainement essayé de dériver TFormHomonyme de uMain en sous classes
    TFormHomonyme1 dans unit1 et TFormHomonyme2 dans unit2 sans succès... et de plus cela semble compliquer abominablement le code... que j'essaie de maintenir simple.

    J'étais sur autre chose. Je regroupe ce que j'ai fait... et on en reparle si vous le voulez bien.

    Merci. Cordialement.
    Gilles
    Dernière modification par Invité ; 07/07/2010 à 20h01.

  4. #4
    Invité
    Invité(e)
    Par défaut
    Revoilà. Bon alors j'ai regardé. Ce qui fonctionne, c'est un truc (j'ai pas d'autres mots sinon ) de ce genre là :
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    unit uMain;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
      unit1, unit2, {....} unitx;
    type
     
      { TFormMain }
       TFormuMain = class(TForm)
        private
          { private declarations }
          Procedure procShow(Sender: TObject;sMess:string);
        public
          { public declarations }
     
     
        end;
     
     
      TFormMain = class(TForm)
        Button1: TButton;
        Label1: TLabel;
        procedure Button1Click(Sender: TObject);
        private
        { private declarations }
     
      public
        { public declarations }
      end; 
     
    var
      FormMain: TFormMain;
     
     
    implementation
     
    {$R *.lfm}
     
    { TFormMain }
    Procedure TFormumain.procShow(Sender: TObject;sMess:string);
    begin
      FormMain.label1.caption:= smess;
    end;
     
    procedure TFormMain.Button1Click(Sender: TObject);
    begin
     
      TFormuMain(Formmain).procShow(nil,'en local');
      Application.CreateForm(Tform1, Form1);
      Form1.Show;
      TFormUnit1(Form1).procShow(nil, 'en appel');
    end;
     
    end.
    et pour chaque unit1, unit2,... unitx
    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
    49
    50
    51
    52
    53
    54
    unit Unitx; 
    
    {$mode objfpc}{$H+}
    
    interface
    
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
    
    type
    
      TFormunitx = class(TForm) // C'est malin !
        private
          { private declarations }
    
        public
          { public declarations }
          Procedure procShow(Sender: TObject;sMess:string);
    
        end;
    
      { TForm1 }
    
      TFormx = class(TForm)
        Button1: TButton;
        Label1: TLabel;
        procedure Button1Click(Sender: TObject);
      private
        { private declarations }
    
      public
        { public declarations }
    
      end;
    
    var
      Formx: TFormx;
    implementation
    uses uMain;
    {$R *.lfm}
    
    Procedure TFormUnitx.procShow(Sender: TObject;sMess:string);
    
    begin
      Formx.label1.caption:= smess;
    end;
    { TForm1 }
    
    procedure TFormx.Button1Click(Sender: TObject);
    begin
       TFormunitx(Formx).procShow(nil,'en local');
    end;
    
    end.

    ... et cela n'a absolument aucun intérêt Pas besoin de la classe dérivée ! On fait la même chose sans : on en revient au code Case Of

    D'un autre côté, il n'est pas question d'utiliser non plus procedure proSshow(Sender: TObject;sMess:string); overload; puisque toutes les procédures sont exactement identiques (dans leurs noms) et dans leurs variables.

    Resterait éventuellement à dériver dans unit1, unit2, ...initx, une TFormHomonyme déclarée dans umain et de la même façon que dans l'exemple ci-dessus on pourrait appeler la procedure contenue... Mais là encore, le code sera différent pour chaque fenêtre... Je crois donc que cela n'a aucun intéret avec les contraintes que je me suis fixé.

    Il semble finalement que c'est une mauvaise idée l'indirection dans ce cas-là... Batyann811, vous partagez cet avis ?

    Merci pour votre aide. Cordialement.
    Gilles
    Dernière modification par Invité ; 07/07/2010 à 20h55.

  5. #5
    Rédacteur
    Avatar de darrylsite
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 299
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 299
    Par défaut
    Il serait bien de prendre le temps de comprendre un peu mieux la programmation objet, et aussi celui utilisé par Free Pascal. ça te permettrait d'avoir du code plus propre.

    Il n'est pas aussi tres propre d'appeler directement les méthodes de tes TForm en dehors de leurs classes.
    En Free Pascal, on utilise la notion de Classe ce qui signifie que les objets sont transmis directement par référence ou par adresse.

    ton premier code peut juste s'écrire comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    var F : TForm;
    begin
      for i := 0 to Screen.FormCount-1 do 
        begin
          F := screen.Forms[i];
          F.Caption := 'Truc '+ IntToStr(i);
          //..............
    Pourquoi le reste du code ne marche pas?
    F est une instance de la classe TForm. Donc tu n'as accès qu'aux méthodes TForm des classes dérivées, les autres méthodes procShow, ... n'existe pas pour un objet de type TForm.

    Pour arriver au résultat que tu veux, il y a deux possibilité :
    • hériter d'une classe abstraite

    • Implementer une interface


    Je vais presenter ici la méthode de l'interface car elle est plus élégante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     IShow = Interface
      procedure procShow(); // pas besoin de l'implémenter
    end;                            //la déclaration suffit
     
    {........}
     Fenetre1 = class(TForm, IShow)
                     public
                       procedure procShow(); // méthode de l'interface à implémenter
                       {...}
                     end;
    Ton code devient alors
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    var
        i  : integer;
        F : TForm;
    begin
      for i := 0 to Screen.FormCount-1 do 
        begin
          F := screen.Forms[i];
          F.Caption := 'Truc '+ IntToStr(i);
          IShow(F).showProc();
        end;
    La méthode showproc de l'interface se charge d'appeler la méthode spécifique à l'affichage de la fenêtre.

    La deuxième solution que je ne vais pas présenter ici pour manque de place, consiste à passer par une classe abstraite.

    [DNK]
    Une des habitudes que j'ai eues en programmation java est d'utiliser une seule classe par fichier. ça aide beaucoup à se retrouver dans un projet contenant plusieurs classes.
    [/DNK]
    Le langage pascal est un langage élégant, alors utilisons le de manière élégante

  6. #6
    Membre chevronné
    Homme Profil pro
    Inscrit en
    Janvier 2010
    Messages
    235
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Janvier 2010
    Messages : 235
    Par défaut
    Pour ton problème de SDI maison je pense que pour faire ce genre de choses il faut passer par la création de composants. Je verrai bien un système avec 2 composants tous les 2 dérivé de TForm. Le premier (disons TFormMaster) serait utilisé comme fenêtre principale et ajouterait à une TForm normale la possibilité de gérer une liste de TFormSlave (le 2eme composant) avec des méthodes genre AddSlave, DeleteSlave. Il aurait en outre la capacité de passer des évenement à tous ses esclaves (genre fermeture, réduction, ...). Le 2eme composant (TSlave) devrait lui s'inscrire auprès de sa fenêtre principale (par AddSlave) à sa création, traiter les messages reçus de sa fenêtre principale et se désinscrire auprès de sa fenêtre principale (parDeleteSlave) lors de sa destruction.

    Je pense qu'un système comme ça doit être faisable avec Lazarus non ? J'ai quand même un doute sur la possibilité de faire l'enregistrement auprès de la fenêtre principale de façon graphique mais au pire ce serait une ligne de code dans le FormCreate de l'esclave.

Discussions similaires

  1. Clés primaires sur des tables externes, alternatives par procédures stockées ?
    Par Jean-Philippe André dans le forum Développement
    Réponses: 18
    Dernier message: 10/07/2012, 17h21
  2. Etablir des liens sur des niuméros pour appels automatiques
    Par zerobug dans le forum Général Dotnet
    Réponses: 3
    Dernier message: 17/11/2008, 11h13
  3. Réponses: 12
    Dernier message: 19/08/2007, 19h26
  4. [SQL-Server] requête sur des procédures stockées
    Par babap1 dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 05/07/2007, 13h23
  5. Réponses: 1
    Dernier message: 26/02/2007, 09h44

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