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 :

Partage d'un formulaire entre deux applications


Sujet :

Composants VCL Delphi

  1. #1
    Membre à l'essai
    Partage d'un formulaire entre deux applications
    Bonjour à tous,

    Je cherche la meilleur technique pour utiliser le même formulaire dans deux applications.
    J'ai un formulaire d'édition des données d'un étudiant. Nom, prénom...
    Je voudrais l'utiliser dans le logiciel étudiant et le logiciel inscription.
    Comment faire ?

    J'ai entendu parler d'un TFrame, es-ce une solution?

    Merci pour vos conseils

    Bertrand

  2. #2
    Membre émérite
    dans une dll, ça le ferait pas ?

    et sinon, qu'est-ce qui empêche d'utiliser le même fichier dans 2 projets différents ?

  3. #3
    Membre à l'essai
    Bonjour papy214,

    Effectivement ta réponse est pertinente.
    Je dois pouvoir insérer mon formulaire étudiant dans un autre formulaire car mon logiciel inscription va par exemple m'afficher les inscriptions de l'étudiant dans la même fenêtre.
    Et oui je sais logiquement je devrais avoir un seul logiciel avec toutes les options mais là c'est une autre histoire.

    Es-ce compréhensible?

    Bertrand

  4. #4
    Membre émérite
    A partir du moment où le TFrame est autonome dans son fonctionnement, rien n'empêche effectivement d'utiliser cette base là.

  5. #5
    Membre à l'essai
    Okay donc le tframe est une solution.

    J'aimerais savoir comment tu travailles, as-tu une autre solution pour arriver à ce résultat. Je joins une image.
    Le but étant que si je change la position de mes éléments dans le form étudiant je ne doive pas le faire dans les deux logiciels.


    Bertrand

  6. #6
    Membre actif
    Comme le dit Papy214, tu peux utiliser le même fichier source qui gère le formulaire dans tes 2 applications.
    Ca m'arrive régulièrement de partager les mêmes sources. Pour plus de clarté, du peux même créer un groupe de projet qui contiendra tes 2 projets.

  7. #7
    Expert éminent sénior
    La TFrame est une approche mais on peut vite avoir des soucis
    Il est vite possible de modifier la Frame héritée dans conteneur ce qui nuira a des modifications ultérieures de la Frame

    Il est aussi très simple d'utiliser une TForm, lui affecter à son Parent le conteneur et retirer les bordures (BorderStyle := bsNone)
    Moins aisée peut-être pour un débutant pour le design (faut ajuster au RunTime)
    Bien plus fiable à long terme

    Je compose bcp de fenêtre ainsi, à partir d'une formulaire commun, je peux changer produire un tas d'écran différent
    C'est l'inverse de ton cas, le contenant est unique et le contenu est variable


    le Conteneur


    un Contenu (en fait, cela transfert les panels de la fenêtre à différent endroits du conteneur, un genre de multi-frame)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //------------------------------------------------------------------------------
    function TModuleReverseDecisionTriMagasinForm.InitializeMode(AModeDock: TWinControl): TSize;
    begin
      Result.Width := pnlMode.Width;
      Result.Height := pnlMode.Height;
      pnlMode.ParentFont := False; // Pour éviter le Zoom
      pnlMode.Parent := AModeDock;
      pnlMode.Left := 0;
      pnlMode.Top := 0;
      pnlMode.BevelOuter := bvNone;


    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 TModuleReverseReceptionObjetForm.Initialize();
    var
      DockedSize: TSize;
    begin
      ...
     
      // 1ere Initialisation
      FDecision.Initialize(Self);
      DockedSize := FDecision.InitializeMode(pnlModeDock);
      AdjustFormWithDockedSize(pnlModeDock, DockedSize);
     
      ...


    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Membre à l'essai
    Bonjour ShaiLeTroll,

    Je comprends l'idée mais je n'arrive pas au résultat désiré.

    Dans un formulaire Tform_index , j'ai créé une : var form_index: Tform_index;
    Et pour le test sur un bouton
    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
    procedure Tform_index.btn_createFormClick(Sender: TObject);
    var
      myForm: TForm;
      LabelBonjour: TLabel;
    begin
      myForm := TForm.Create(application);
      myForm.Parent := form_index;
      myForm.ParentFont := False; // Pour éviter le Zoom
      myForm.left := 0;
      myForm.Top := 0;
      //myForm.BevelOuter := bvNone; //crash :-(
     
      LabelBonjour := TLabel.Create(application);
      LabelBonjour.Parent := myForm;
      LabelBonjour.Caption := 'sqqfsdfsdfsfd';
     
    end;


    Je ne comprends pas bien dans quoi je dois créer : TForm.Create(application);

    Bertrand

  9. #9
    Expert éminent sénior
    le code serait plutôt ceci


    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
    procedure Tform_index.btn_createFormClick(Sender: TObject);
    var
      myForm: TForm;
      LabelBonjour: TLabel;
    begin
      myForm := TForm.Create(Self);
      myForm.Parent := Self;
      myForm.left := 0;
      myForm.Top := 0;  
      myForm.BorderStyle := bsNone;
     
      LabelBonjour := TLabel.Create(myForm);
      LabelBonjour.Parent := myForm;
      LabelBonjour.Caption := 'sqqfsdfsdfsfd'; 
     
      myForm.Show(); // Euh, je ne sais plus si il y en a besoin ou pas
    end;


    Tu as confondu le BorderStyle d'une TForm et le BevelOuter d'un TPanel
    Evite d'utiliser la variable globale form_index, c'est un risque, le Self donne l'instance en cours

    plus tard TForm sera ta fenêtre TFormLogin
    TFormLogin contiendra déjà les Labels et Edit nécessaire avec un bout de code qui gère la connexion
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  10. #10
    Membre à l'essai
    C'est nickel, exactement ce je voulais.

    Un grand merci pour ta réponse.

    Bon week-end

  11. #11
    Membre à l'essai
    Bonjour,

    Je rouvre ce post.
    J'ai donc modifié une application sur base d'un formulaire.conteneur qui va charger un autre formulaire.enfant
    Question.
    Dans mon formulaire conteneur je charge TUser = class(TObject)
    Elle va me donner le login.windows puis via une requête dans un AD (active directory) le nom, prénom et une sorte d'ACL => es-ce un directeur...
    De cette façon je sais ce que l'utilisateur peut réaliser comme action.

    Je charge mon formulaire enfant dans le conteneur. Même combat je vais avoir besoin de mon object TUser.
    Le formulaire enfant pouvant être chargé dans une autre application, je ne peux pas juste aller chercher mon TUser dans mon conteneur.

    Du coup je vais recréer un TUser dans mon formulaire enfant.
    Je voudrais naturellement éviter de le recréer s'il existe déjà dans mon application, sorte de variable globale.
    J'ai réalisé quelques tests pour le moment mais je n'arrive à rien de bon.

    Comment faire ?

    Merci pour votre aide.

    Bertrand

  12. #12
    Expert éminent sénior
    voilà, tu pointes le truc un peu compliqué quand tu partages des fiches, elles sont rarement autonomes et il est très tentant de faire référence aux autres unités de l'application qui n'existe pas forcément dans l'autre application.

    il y a plusieurs approches possibles, en voici une que j'utilise de façon assez efficace

    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
     
    unit FormPartagee;
     
    type
      ISource = interface
        function GetID: Integer;
        function GetName: string;
      end;
     
      TFormPartagee = class(TForm)
      ...
      private
        Source: ISource;
      public
        class function Execute(Sender: TComponent; Source: ISource): TFormPartagee;
      end;
     
    implementation
     
    class function TFormPartagee.Execute(Sender: TComponent; Source: ISource): TFormPartagee;
    begin
      Result := TFormPartagee.Create(Sender);
      Result.Source := Source;
      Result.Show();
    end;


    et du côté appelant

    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
     
    type
      TMainForm = class(TForm, ISource)
    ...
        function GetID: Integer;
        function GetName: string;
      end;
     
    procedure TMainForm.Button1Click(Sender: TObject);
    begin
       with TFormPartagee.Execute(Self, Self) do
      begin
       Parent := Self;
      end;
    end;


    avec ce principe ISource permet de s'assurer que la fiche partagée aura toutes les informations dont elle a besoin (à définir selon les besoins) et cela peut être la fiche principale mais aussi tout autre objet supportant les interfaces selon les besoins.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  13. #13
    Expert éminent sénior
    Ce principe d'interface est exactement ce que je faisais pour les écrans montrés en exemple
    La fenêtre conteneur implémentait une IReception
    Les fenêtres ancrables implémentant une IDecision (et d'autres interfaces variant selon le business)
    Avec une structure d'appel avec aussi une class function Execute
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  14. #14
    Membre à l'essai
    Bonjour Paul, ShaiLeTroll

    Merci pour vos réponses.
    Je vais essayer le code, il faut que je vois comment le code fonctionne.

    Bonne journée

    Bertrand

  15. #15
    Membre émérite
    Voici un exemple qui peut te donner des idées


    Serialize extrait le DFM dans la fichede droite
    Deserialise regénère le dfm de la fiche de gauche



    tu peux par exemple modifier un composant
    ou en ajouter un second

    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
     
      object Edit1: TEdit
        Left = 48
        Top = 24
        Width = 121
        Height = 21
        TabOrder = 0
        Text = 'Ligne 1'
      end
      object Edit1a: TEdit
        Left = 48
        Top =50
        Width = 121
        Height = 21
        TabOrder = 0
        Text = 'Ligne 2'
      end

  16. #16
    Membre à l'essai
    Bonjour,

    je viens de tester le code "interface"
    J'ai en premier essayé de comprendre celui sur http://www.delphibasics.co.uk/Article.asp?Name=Interface
    Puis votre version du 22/01/2020, 16h48

    Citation Envoyé par Paul TOTH Voir le message

    avec ce principe ISource permet de s'assurer que la fiche partagée aura toutes les informations dont elle a besoin (à définir selon les besoins) et cela peut être la fiche principale mais aussi tout autre objet supportant les interfaces selon les besoins.
    Donc si je comprends bien de cette façon je m'assure que la unit FormPartagee trouvera les functions GetID et GetName dans le formulaire parent -> TMainForm ?
    Bon après il n'y a pas d'interaction directe avec les functions ? Rien n'oblique que j'exécute les functions ?

    Je voudrais m'assure de prendre la bonne direction pour la suite.
    Dans TMainForm
    Je crée un
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    TUser = class
        name: string;
        firstName: string;
        nameFirstName: string;
        username: string;
        idPers: string;
        admin: Boolean;
        superAdmin: Boolean;
        backgroundPathImg: string;
        memberOf: TStringList;
        ....


    le but étant de le récupérer dans FormPartagee

    Dans le mainForm
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    with TFormPartagee.Execute(Self, Self) do
      begin
        usernameStringTest := MainForm.mainUsername; //string non lié a TUser -> je récupère bien la string du parent vers l'enfant
        user := MainForm.user; //class TUser -> ne passe pas :-(
        Parent := Self;
        top := 30;
        Left := 30;
      end;


    Dans
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    TFormPartagee = class(TForm)
        edt_username: TEdit;
        procedure btn_getIDClick(Sender: TObject);
        procedure FormShow(Sender: TObject);
      private
        { Private declarations }
        Source: ISource;
      public
        { Public declarations }
        usernameStringTest : string;
        user : TUser;
        class function Execute(Sender: TComponent; Source: ISource): TFormPartagee;
      end;


    je n'ai pas de user := TUSer.create(); dans le formulaire TFormPartagee
    Vous aurez vite compris que je suis perdu :-(

    Merci pour votre temps

    Bertrand

  17. #17
    Expert éminent sénior
    oui c'est la bazar là

    on reprend

    s'il est possible de tout mettre dans un TUser, alors c'est encore plus simple

    Unit1 déclare la première fiche
    Unit2 la seconde fiche
    UnitUser.pas déclare TUser

    la fiche principale instancie un TUser qu'elle passe à la fiche secondaire, et là c'est sans soucis car Unit2 dépendra de UnitUser sans connaitre Unit1

    ce que je proposais avec l'Interface c'est tout autre chose, une interface c'est un ensemble de méthode qui existent dans un objet dont on ne sait rien. Bien souvent on se content de prendre la classe parent, par exemple un TCanvas peut être un TBitmapCanvas, un TPrinterCanvas, un TControlCanvas...on s'en fiche, on les traitent tous comme un TCanvas sans savoir sur quoi ils opèrent...mais pour que ça fonctionne cela impose que tous les TXXCanvas héritent de TCanvas.

    Avec les Interface, je peux définir un ensemble de méthodes que l'objet doit implémenter, quelque soit son ancêtre.

    on pourrait définir par exemple

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    type
      IUserOwner = Interface
        function GetUser: TUser;
      end;


    avec ça je peux récupérer le TUser de n'importe quel objet qui possède une méthode GetUser ET qui déclare implémenter l'interface IUserOwner, je n'ai aucune autre contrainte...ça peut être un dérivé de TForm, de TDataModule, de TFrame, ou de n'importe quoi d'autre, je m'en fiche. Tout ce que je sais c'est qui est déclaré comme ceci

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    type
      TQuelqueChose = class(TUnAncètre,  IUserOwner)
        ...
        function GetUser: TUser; // obligatoire pour compiler car on a déclaré qu'il implémente IUserOwner
      end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  18. #18
    Membre à l'essai
    Bonjour Paul,

    Je continue la logique parent, enfant.
    J'ai mon Tuser que je passe du parent vers l'enfant, check.
    Question suivante, au niveau d'une connexion base de données.

    Dans un fichier de config.ini j'ai ma connexion vers la db.

    j'ai un composant tibo_database sur mon parent qui va lire la config dans config.ini via l'évènement beforeConnect
    Dans mon enfant tibo_query.maConnexion va chercher le tibo_database sur monParentForm.maDatabase
    Encore une fois c'est quand je connais le nom du formulaire parent.

    Dans mon idée de fichier lib je ne connais pas le parent.
    Donc j'ai essayé de passer ma connexion db de la même façon que mon Tuser (self.user étant le parent et horaireFrm l'enfant)
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    horaireFrm := TMain.Create(application);
      horaireFrm.user := Self.user;
      horaireFrm.config := Self.config;
      horaireFrm.database :=  ibdtbs_database;

    Et bien le tibo_query sur l'enfant il n'aime pas. Car il veut un paramètre IB_connection dès le départ.

    Donc ma question, es-ce que je dois créé un tibo_database sur chaqu'un de mes forms ?
    Ou sinon comment lui passer une connexion du patrent vers l'enfant sans utiliser le nom du parent.

    Ca reste compréhensible ?

    Bonne journée

    Bertrand

  19. #19
    Rédacteur/Modérateur

    Les connexions aux données seraient dans un datamodule utilisé par les formes ce serait quand même mieux non ?
    La seule chose absolue dans un monde comme le nôtre, c'est l'humour. » Albert Einstein

    Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Tokyo, Rio) et peut être quelques autres
    SGBD : Firebird 2.5, 3, SQLite
    générateurs Etats : FastReport, Rave, QuickReport
    OS : Window Vista, Windows 10, Ubuntu, Androïd

  20. #20
    Membre à l'essai
    Oui pourquoi pas, mais le dataModule devra également avoir toujours le même nom ?
    Tu utilises quel nom ?

    Bertrand