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 :

Utiliser les "user messages" (W/LM_USER+xyz) [Lazarus]


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut Utiliser les "user messages" (W/LM_USER+xyz)
    Bonjour,

    J'ai besoin de faire communiquer des TFrames entre elles et aussi vers/depuis la fiche principale. Après m'être pris une quantité hallucinante d'Access Violations (normal, la complétion de code à partir d'une frame me propose les objets publiés par une autre frame, mais la moindre tentative de lecture --> AV !), j'ai trouvé une discussion pour Delphi ultra légère pour mettre en œuvre une solution simple à base de ces user messages, tout ce que j'aime

    Vite vite un coup de copier/coller vers mon Linux Laz1.4, mise en place du projet comme le monsieur explique, F9, exécution, clic sur le bouton et... rien
    Transport du projet sous XP (Laz 1.6), F9, le bouton et... encore rien

    Après des recherches et la lecture d'une page au nom évocateur (Lazarus For Delphi Users, ça m'a rappelé un vieux tuto qui expliquait comment passer de VB [3, à l'époque] à Delphi), tout en bas peut-être la solution...

    Pas beaucoup de lignes à lire, pour un sujet aussi important ça n'inspire pas confiance, mais il y a un lien, alors cliquons en croisant les doigts (oui, parce que le nombre de fois où à partir de l'aide je gagne des http404, là aussi je pourrais faire une belle collec'), découvrons la page qui s'affiche et là, stupeur en ce qui concerne mon problème :
    FAQ
    Processing user messages in your window
    write me
    C'est tout.
    Depuis janvier 2015 au moins.
    Merci les gars...

    Et ici, quelqu'un sait comment faire fonctionner les user messages ?
    Parce que sinon, c'est tout mon projet qui part à la poubelle...

    Merci de vos retours,

  2. #2
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    Salut,

    Peut-être que ce tuto t'aidera.
    S'il y a quelque chose que tu ne comprends pas, repose ta question après la lecture.

  3. #3
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Salut anapurna,

    Merci pour le lien,
    Citation Envoyé par anapurna Voir le message
    peut-être que ce tuto t'aidera
    si tu as quelque chose que tu comprends pas, repose ta question après la lecture
    mais manque de bol, les messages sous Lazarus ça ne doit pas juste être du copier/coller depuis du code Delphi (et un peu d'adaptation), c'est surement beaucoup plus compliqué que ça.

    Dans ton tuto, comme je l'avais déjà un peu pratiqué à l'époque de Delphi, je suis allé directement à l'exemple de la fin, j'ai généré les 2 exe's (après un peu de bricolage) mais s'ils se lancent bien, ils ne se causent pas...

    Quant à mon problème, par exemple je crée une frame, je la pose sur une form avec un TEdit et dans sa procédure OnChange je mets unitFrame.Frame1.SendDataMsg;Ensuite, de l'autre côté, dans la frame, j'ai ça :
    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 TFrame1.SendDataMsg;
    var
      aForm: TCustomForm;
      hwnd: THandle;
    begin
      aForm := GetFirstParentForm(Self);
      if aForm <> nil then
        aForm.Perform(LM_MONJOLIMESSAGE, 0, 0); // non exécuté, d'où les tentatives suivantes :
      hwnd := 0;
      //hwnd := Frame1.GetParentHandle; // AV !
      // ou
      if Frame1.Parent.Handle <> 0 then
        hwnd := Frame1.Parent.Handle; // AV !
      // suite enlevée pour ne pas alourdir le post
    end;
    Je clique dans l'edit, je tape sur une touche et voilà ! AV ! Une frame n'est pas foutue de récupérer le handle de son parent
    L'idée vient de là.

  4. #4
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    Salut,

    OK tu veux créer ton propre message.
    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
     
    const
      WM_MONJOLIMESSAGE = WM_USER + 1;
     
    TMyForm = Class(TForm)
    ....
     procedure OnMONJOLIMESSAGE(var Msg: TMessage); message WM_MONJOLIMESSAGE;
    ....
    End;
    ...
     
    procedure TMyForm.OnMONJOLIMESSAGE(var Msg: TMessage);
    begin
      ... ici je fais ce que je veux quand je reçois mon message
    end;
    Pour exécuter le message :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     PostMessage(self.Handle,WM_MONJOLIMESSAGE,0,0);

  5. #5
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Citation Envoyé par anapurna Voir le message
    ok tu veut créer ton propre message
    Non !
    Ça, je sais faire. J'ai déjà fait, il y a longtemps, en D7.

    Citation Envoyé par anapurna Voir le message
    pour exécuter le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     PostMessage(self.Handle,WM_MONJOLIMESSAGE,0,0);
    Là je ne comprends pas : self c'est soi, ça revient à s'envoyer un message à soi-même1, comme si je rédigeais un courrier sur du papier, que je le mettais dans une enveloppe avec mon adresse écrite dessus, que je mette un timbre et que je l'apporte à la Poste pour que ça me revienne 2 jours plus tard, ou plus, ou même jamais, des fois...
    J'ai plus vite et mieux fait de le mettre directement dans ma boîte aux lettres,

    Ce que je veux c'est envoyer un message d'une frame à une autre et là, c'est mort de chez mort, pour le moment, sauf si on aime les AV...

    ---
    1 : j'ai d'ailleurs fait le test suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TMain.FormShow(Sender: TObject);
    begin
      Caption := IntToStr(self.Handle);
    end;
    procedure TMain.Button2Click(Sender: TObject);
    begin
      PostMessage(self.Handle, WM_MONJOLIMESSAGE, self.Handle, 0);
    end;
    procedure TMain.OnMONJOLIMESSAGE(var Msg: TMessage);
    begin
      ShowMessage('message reçu ' + IntToStr(Msg.WParam));
    end;
    Et que crois-tu qu'il arrivât ? Ben c'est le même handle qui s'affiche dans la barre de titre de la fiche et dans le MessageBox, confirmant ce que je disais + haut. Aucun intérêt, donc, sauf didactique.

    Bon, j'y retourne...

  6. #6
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    Salut,

    Ton exemple est simpliste mais c'est normal, tu passes le handle de la forme principale et tout ceci se passe dans cette forme.

    Les frames sont posées sur la même forme principale, non ? Dans la même application ?

    Donc si je comprends bien, tu veux passer ton message dans ta frame. Pour moi, la forme principale sert de hub pour tes messages.
    Disons que je cherche la logique que tu veux mettre en place.
    As-tu essayé ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    TMFrame1 = Class(TFrame)
    ...
    procedure OnMONJOLIMESSAGE(var Msg: TMessage); message WM_MONJOLIMESSAGE;
    ...
    End; 
    ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    procedure TMFrame1.OnMONJOLIMESSAGE(var Msg: TMessage);
    begin
      ShowMessage('message reçu ' + IntToStr(Msg.WParam));
    end;

  7. #7
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Salut,

    plusieurs choses à dire :
    - la première, c'est que si je suis parti sur les messages c'est suite à ton tuto,
    - la deuxième, c'est qu'au final et en y réfléchissant bien, les événements ne sont que des messages (un peu bordéliques à gérer, pour moi).
    - la troisième, c'est que je viens de voir le bout du tunnel avec ce tuto, à condition de prendre en compte les points suivants :

    -- Linux on peut oublier, SendMessage n'y fonctionne pas comme sous Windows (à tel point que c'est AV systématique) ;
    EDIT : j'ai retrouvé l'image que j'ai prise lorsque j'ai essayé de comprendre en avançant en pas-à-pas. Des fois que ça intéresserait quelqu'un :
    Nom : av_sur_sendmessage.png
Affichages : 277
Taille : 35,4 Ko
    C'est sur la ligne lisible juste au dessus de la fenêtre d'erreur que ça plante, et ça se trouve dans gtk2proc.inc.

    -- sous Windows (XP SP2 en ce qui me concerne), SendMessage ne fonctionne pas en mode BroadCast (), l'émetteur doit utiliser le handle de l'appli destinatrice du message ; je n'ai pas creusé plus avant (oui, je sais, il faudrait, mais j'ai d'autres chats à fouetter...)

    Voilà une jolie image pour illustrer tout ça :
    Nom : tuto_ok.png
Affichages : 303
Taille : 44,5 Ko

    Quelques mots sur comment ça se passe, en mode "télégraphique" :
    Emetteur envoie Message1 depuis btnDemarrer "à condition d'utiliser le handle du destinataire" !
    Recepteur le reçoit dans DefaultHandler et acquiesce avec Message2 qui contient son propre handle.

    Emetteur reçoit ce Message2 dans DefaultHandler et le confirme en renvoyant un Message3 contenant son handle et celui du TEdit avec lequel on veut travailler.

    À réception de ce Message3 par récepteur, celui-ci envoie au TEdit de l'émetteur l'ordre de mettre dans la chaîne "MonTexte" le texte se trouvant dans sa zone de texte, qui va être recopié dans le label2.Caption du récepteur.

    Pour faire fonctionner et observer toute cette mécanique :
    1- on lance un "project1.exe" qu'on passe en récepteur ;
    2- on lance un autre "project1.exe" et on va remplir sa zone "HWND Appli Ext" avec le handle du récepteur, affiché dans sa barre de titre, puis on clique sur "btnDémarrer".

    Voilà.
    Dans le zip (testé), tout ce qu'il faut pour jouer, j'ai même laissé des vieux commentaires : tutodvlp.zip

    Allez, ça ira bien comme ça, je suis vanné, du coup !
    Mais je vais cliquer sur
    Merci à tous, et on peut continuer à discuter.

    PS : désolé pour la faute d'orthographe, "Status" ça s'écrit avec un "t", mais je ne vais pas refaire l'image, j'en ai un peu marre, là, ce soir...

  8. #8
    Membre Expert
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Billets dans le blog
    2
    Par défaut
    Bonsoir, encore un sujet bien intéressant et de quoi se faire encore plus de cheveux blanc.

    Alors j'ai compilé ton exemple sous Windows 10 64bit et La dernière version téléchargeable de Lazarus
    voila ce que j'ai remarqué dans :

    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
    procedure TForm1.WndProc(var Message: TLMessage);
    begin // http://forum.lazarus.freepascal.org/index.php?topic=14939.0
      if not (csDesigning in ComponentState) then
      begin
        case Message.Msg of
          LM_USER+1:
            //with TLMessage(Message) do
            with Message do
              ShowMessage('In the Form' + intToStr(WParam) +' '+ PChar(LParam));// 17 This is a message YAISSE !
     
          LM_USER+2:  
            //with TLMessage(Message) do
            with Message do
              ShowMessage('In The frame ' + intToStr(WParam) +' '+ intToStr(LParam));// 17 This is a message YAISSE !
        end;
      end;
      inherited; // important to forward messages do default handlers
    end;
    LM_USER+2 n'est jamais appelé car la form et la frame non pas le même handle, et c'est la frame qui reçois le message
    cf :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure TFrame1.MessageReceiver(var msg: TLMessage);
    begin // http://www.swissdelphicenter.ch/de/showcode.php?id=163
      with Msg do
      begin
        Edit1.Text := IntToStr(Msg) + ' '+ IntToStr(WParam) + ' '+ IntToStr(LParam);
        ShowMessage('In The frame ' + intToStr(WParam) +' '+ intToStr(LParam));
      end;
    end;
    Ici :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      // pas vu de diff
      // aText: string = 'This is a message';
    Paf dans les dents, un bon gros SIGSEGV

    Dans :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    procedure TFrame1.Button1Click(Sender: TObject);
    var
      aMess: TLMessage;
    begin
      //ExecOnEvent('petit test from ' + Self.Name); // "... from FrameTest", yaisse !
      with TLMessage(aMess) do begin
        Msg := LM_USER+1;
        WParam := length(aText);
        LParam := integer(pchar(aText));
      end;
      Parent.Perform(aMess.Msg, aMess.WParam, aMess.LParam);
      //PostMessage(Parent.Handle,aMess.Msg, aMess.WParam, aMess.LParam);
    end;
    Idem SIGSEGV et idem avec postmessage
    "fpc_pchar_to_ansistr ......"

    Alors me dis vus que je suis en 64bit je change LParam := integer(pchar(aText)); par Int64
    Et la miracle ton exemple marche nickel (avec postmessage aussi)

    Tout fonctionne, je comprend pas ou çela te bloque maintenant ? (un peu fatigué aussi a cette heure )

    Bonne fin de soirée
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  9. #9
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Bonjour,
    Citation Envoyé par BeanzMaster Voir le message
    Bonsoir, encore un sujet bien intéressant et de quoi se faire encore plus de cheveux blanc.
    Grand merci pour cette petite phrase1 que je prends comme un compliment (sauf pour les cheveux blancs, mais les miens ne veulent pas sortir, ouf )

    Citation Envoyé par BeanzMaster Voir le message
    Alors me dis vu que je suis en 64bit je change LParam := integer(pchar(aText)); par Int64
    Et là miracle ton exemple marche nickel (avec postmessage aussi )
    Grand bravo pour cette trouvaille qu'il va falloir que j'intègre avec des {$IFDEF ...} sans doute mais je ne sais pas encore comment...

    Citation Envoyé par BeanzMaster Voir le message
    Tout fonctionne, je comprend pas où çela te bloque maintenant ? (un peu fatigué aussi à cette heure )
    Grand point d'interrogation dans ma tête car, comme je le disais à anapurna, j'ai abandonné sa combine d'events pour me tourner vers la mienne que je maîtrise beaucoup mieux, et rien ne me bloque.
    Le zip est là juste parce qu'il me l'a demandé, pour essayer de trouver là où je coinçais dans mes essais avec sa manière de faire.
    Mais ma manière fonctionne, alors tout va bien -- et en plus le soleil est revenu

    Bonne journée bon week-end,
    ---
    1 : si le sujet t'intéresse, j'ai posé là une question assez générique concernant la gestion des messages, et j'ai peur de ne pas avoir beaucoup de réponses... N'hésite pas à aller jeter un œil.

  10. #10
    Membre Expert

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Par défaut
    Salut JP.

    j'ai posé là une question assez générique...
    Je vais te répondre ici (ou tenter de te répondre) pour donner un exemple sous Lazarus.

    Prenons un message système généré par le bouton gauche de la souris : WM_LBUTTONDOWN.
    Il y a plusieurs façons de l'intercepter :
    1) dans la procédure WndProc
    2) dans une procédure qui ne gère que ce message
    3) pour nous faciliter la vie, dans l'événement OnMouseDown (événement déclenché par la réception du message).

    C'est en fait l'ordre dans lequel le message est réceptionné. Bien évidemment, on n'utilisera qu'une méthode, c'est juste pour s'assurer de l'ordre.

    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
    private
       procedure OnLeftButton(var Message: TMessage); message WM_LBUTTONDOWN;
    protected
        procedure WndProc(var Message: TMessage); override;
    //...
    procedure TForm1.WndProc(var Message: TMessage);
    begin
        if Message.Msg = WM_LBUTTONDOWN then ListBox1.Items.Add('wndproc');
        inherited; // OBLIGATOIRE
    end;
     
    procedure TForm1.OnLeftButton(var Message: TMessage); // procédure spécifique au message
    begin
       ListBox1.Items.Add('procédure OnLeftButton');
       inherited; // FACULTATIF
    end;
     
    procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    // événement OnMouseDown de Form1
    begin
       if Button = mbLeft then
         ListBox1.Items.Add('event');
    end;
    Bouton gauche sur la fiche.
    Dans le ListBox :
    WndProc
    puis procédure OnLeftButton
    puis event.

    C'est la procédure WndProc qui est chargée de la réception des messages.
    Comme le message y est mentionné, il y a traitement.
    Le inherited placé après va déclencher la suite du traitement du message dans la procédure spécifique. Mais comme cette procédure mentionne aussi inherited, le traitement va encore se poursuivre dans l'événement !
    Si j'enlève l'inherited (facultatif) dans la procédure OnLeftButton, l'événement ne sera pas appelé.
    Par contre, inherited est absolument OBLIGATOIRE dans la procédure WndProc. Si il est en début de procédure, c'est d'abord le traitement spécifique qui va s'exécuter.
    Dans le ListBox :
    procédure OnLeftButton
    puis event
    puis WndProc.

    Donc si tu traites un message dans la procédure WndProc, voici ce que je préconise grandement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure TForm1.WndProc(var Message: TMessage);
    begin
        if Message.Msg = WM_LBUTTONDOWN then ListBox1.Items.Add('wndproc') // message système
        else
        if Message.Msg = MYMESSAGE then ListBox1.Items.Add('wndproc mymessage') // message user
        else
          inherited;                                                          
    end;
    Pour les messages user, je préfère utiliser une procédure spécifique (question de goût).

    Remarque : la procédure DefaultHandler n'est appelée que lorsqu'il n'y a pas de traitement prévu pour le message. Ainsi, pas d'appel pour le message système, mais appel pour le message user.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TForm1.DefaultHandler(var Msg);
    begin
      if TMessage(Msg).Msg = WM_LBUTTONDOWN then ListBox1.Items.Add('defaulthandler'); 
      if TMessage(Msg).Msg = MYMESSAGE then ListBox1.Items.Add('defaulthandler mymessage');
      inherited;
    end;
    Je ne sais pas si j'ai été très clair, alors n'hésite pas...

    Amicalement
    Thierry

  11. #11
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Bonjour,

    Ça avance, ça avance.. Doucement mais ça avance : je crée des frames dynamiques, c'est contraignant au niveau du design mais c'est sympathique à l'utilisation, et je commence à réussir à envoyer un message d'une frame à l'autre en passant par un bureau de poste centralisé qui sert de dispatch sur la mainform.

    Mon problème c'est que je ne sais pas ce que je fais, dans le sens où, au final, les noms des objets et des procédures ne sont pas parlants du tout

    Par ailleurs, J.P, cette idée d'adresser directement le TEdit sur la frame ne me plaît pas du tout : je préférerais quelque chose de plus générique, un message à destination de la frame, à charge pour elle de le gérer, quelque chose du genre ExecOnEvent(sMess, iSrc, iDst);
    Ça commence à fonctionner, mais je m'y perds avec ces histoires d'identification d'objets pour savoir qui fait quoi.

    Prenons un exemple :
    je ne sais plus s'il vient d'anapurna, trouvé sur le web, etc., et donc :
    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
      TFrame1 = class(TFrame)
        Button1: TButton;
        Edit1: TEdit;
        Panel1: TPanel;
        procedure Button1Click(Sender: TObject);
      private
        fOnEvent : TOnMyEvent;
      public
        Property OnEvent: TOnMyEvent read fOnEvent write fOnEvent;
        Procedure ExecOnEvent(const StrMess: String; const src,dst: integer);
      end;
     
    implementation
     
    {$R *.lfm}
     
    procedure TFrame1.Button1Click(Sender: TObject);
    var
      aForm: TCustomForm;
    begin
      ExecOnEvent('Message de', 1, 3);// 1 parce qu'on est sur la fr1, 3 pour envoyer vers la fr3
      aForm := GetFirstParentForm(Self);
      if aForm <> nil then
        PostMessage(aForm.Handle, WM_TEST, self.Handle, 0);
    end;
     
    Procedure TFrame1.ExecOnEvent(const StrMess: String; const src,dst: integer);
    begin
      if assigned(fOnEvent) Then fOnEvent(Self,StrMess,src,dst);
    end;
    C'est quoi ce ExecOnEvent dans le sens ça fait quoi ? Ça reçoit ? Ça envoie ? Je n'en sais rien. On dirait que ça envoie, mais comment ?
    Pareil pour la Property OnEvent: TOnMyEvent read fOnEvent write fOnEvent; si read et write pointent sur le même machin (qui lui, pointe sur le type dans uData :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Type
      TOnMyEvent = Procedure(Sender: TObject; const StrMess: String; const src,dst: integer) of object;
    ), je ne sais pas comment distinguer le read du write, et je pense que mes gros soucis viennent de ces lacunes.

    Merci à vous de les combler, à moins que je ne trouve un tuto qui va bien, mais par exemple, celui fourni par anapurna dans sa première réponse ne fonctionne pas (j'ai réussi hier soir à pas d'heure à avoir un label qui changeait de caption mais c'est tout...)

    Pour en revenir à ces noms "parlants", j'ai changé dans une des frames ce ExecOnEvent par un OnReceiveMessage, ça fonctionne mais c'est peut-être pas bon et j'ai peut-être complètement tort : je n'en sais rien, j'y vais à tâtons, je change un truc et je vois ce qui se passe (AV, rien, ça fonctionne, etc.)
    Par exemple, j'ai viré tous ces JOLIMESSAGE et autres MESSAGE_x pour ne conserver qu'un seul WM_TEST et ça fonctionne. Alors à quoi servent plusieurs messages ?

    Ah lala, que de questions que de questions...

  12. #12
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    Salut,

    tu confonds un peu tout.
    Les messages et les événements ne sont pas du tout la même chose.

    Les message sont asynchrones, c'est-à-dire qu'il sont placés dans une file d'attente et ne seront exécutés qu’après les autres messages déjà présents.
    Il existe des moyens pour forcer et donner des priorités mais le principe est là .

    Les événements c'est l'histoire des properties (propriété) (OnClick... onEvent...). Pour pouvoir utiliser les propriétés avec des événements, il faut créer un type de fonction et/ou procedure of object. Le read et le write autorisent l'affectation ou non de cette méthode ; dans notre cas il faut pouvoir affecter (write).
    Si tu lis mon code, je crée une variable Global en private à l'object du type de la fonction fon... Et ensuite, dans la property, je fais référence à cette variable.
    Pour l'affectation sous Lazarus, on s'aperçoit que l'on affecte l'adresse de la méthode, d'où le @.

    Rien ne t’empêche de passer en paramètre une variable à la méthode.
    Autre chose, la source c'est souvent le sender donc tu peux te servir de lui pour définir qui a envoyé l’événement.

    Plus j'y pense et plus je me dis que ton problème ressemble au design pattern Observer.

  13. #13
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Ola !
    Citation Envoyé par anapurna Voir le message
    salut

    tu confonds un peu tout
    [...]
    Oh, tu sais, c'est fort probable que je me fasse des nœuds dans la tête, faut dire aussi qu'avec ce que je vis, rien n'est simple.

    Regarde : tu m'as indiqué un tuto dans ton premier post, ce matin je le reprends à tête reposée, le premier exemple fonctionne, je m'amuse à changer le nom de la proc juste pour jouer et vérifier que ça peut le faire (genre changer WMCHAR en Recup_Clavier, c'est + parlant -- et aussi parce que je doute de tout, maintenant), juste que le monsieur a oublié de préciser qu'il ne fallait surtout pas d'autres composants sur la fiche, sinon il y en a un qui va prendre le focus (un bouton par ex.) et la récup des touches ne fonctionnera plus.
    Tu passes du temps là-dessus avant de capter...

    Ensuite, chapitre V, la communication inter-applis, bon c'est simple ça ne fonctionne pas. D'après l'auteur ça fonctionne et chez moi, il ne se passe rien sous Windows et ça part en AV sous Linux. Alors, pb Lazarus vs Delphi ou pb Jipété ?
    Pourtant il n'y a quasiment rien :

    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
    procedure TMainFrame.DefaultHandler(var Msg); // reçoit tous les messages
    begin
      inherited DefaultHandler(Msg);
      if (TMessage(Msg).Msg = UnIdentifiantDeMessage) then begin
        if (TMessage(Msg).WParam) = 1 then begin // check du param envoyé par l'émetteur
          ShowMessage(IntToStr(TMessage(Msg).Msg)); // action en fonction du message
        end
        else
          Label1.Caption := 'Message reçu';
      end;
    end;
     
    procedure TMainFrame.btnEnvoyerMessClick(Sender: TObject);
    begin // si on est l'émetteur
      // déjà dans FCreate (mix émet/récep)
    //  UnIdentifiantDeMessage := WM_USER+1;//RegisterWindowMessage('MessageUB45');
      SendMessage(HWND_BROADCAST, UnIdentifiantDeMessage, 1, 0);
    end;
     
    procedure TMainFrame.FormCreate(Sender: TObject);
    begin // si on est le récepteur
      UnIdentifiantDeMessage := WM_USER+1;//RegisterWindowMessage('MessageUB45');
    end;
    et je gagne l'AV en cliquant sur le bouton. J'ai beau commenter toute la proc de DefaultHandler (tant pis pour la réception dans un premier temps), c'est pareil.
    Et le pire c'est que si je remplace le SendMessage d'origine par un PostMessage, ça ne fonctionne pas mieux alors que dans d'autres progs je peux le faire fonctionner, ce PostMessage (pas testé avec le Send dans les autres progs).

    Et qu'est-ce que je peux bien faire face à ça, moi, à part passer un temps dément à comparer mot à mot les progs qui fonctionnent avec celui qui coince ?


    Citation Envoyé par anapurna Voir le message
    plus j'y pense et plus je me dis que ton problème ressemble aux design pattern Observer
    Mais de quoi tu parles, là ?
    Tu ne trouves pas que c'est suffisamment compliqué et prise de tête comme ça ? Tu veux en rajouter une couche ?
    Je vais finir à l'asile avec tout ça, moi...

  14. #14
    Membre Expert

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Par défaut
    Salut JP.

    J'avoue que je ne saisis pas très bien où se situe le problème...

    Si l'on suppose que ta fiche gérant les frames s'appelle Form1, celle-ci n'a pas besoin d'envoyer de messages aux frames, elle peut directement appeler une procédure publique (spécifique à chaque frame).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Frame1.Execute('hello');
    end;
    Par contre, à la fin du traitement, la Frame va devoir envoyer un message à son parent (Form1) pour lui signaler que l'exécution a été faite (ceci permet à l'unité de la Frame de ne pas utiliser l'unité de Form1, ce qui me parait préférable). Par exemple, le message LM_MESSAGEFROMFRAME (défini dans une unité spécifique reférencée dans les unités de Form1 et de chaque Frame).

    Dans l'unité spécifique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    const
      LM_MESSAGEFROMFRAME = LM_USER + 1;
    Dans l'unité de Frame1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TFrame1.Execute(S: string);
    begin
       // traitement...
       //puis envoi du message
       (Parent as TWinControl).Perform(LM_MESSAGEFROMFRAME,Self.Handle,0);
    end;
    Dans l'unité de Form1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    private
        procedure MessageFromFrame(var Msg: TMessage); message LM_MESSAGEFROMFRAME;
     
    //...
     
    procedure TForm1.MessageFromFrame(var Msg: TMessage);
    begin
      // réception du message
      If Msg.WParam = Frame1.Handle then
        Frame2.Execute(Frame1.Edit1.Text, clRed) // mise à jour de Frame2
      else
      // ...
    end;

    A noter que tu peux, par exemple, envoyer le message à partir d'un événement OnChange d'un Edit placé sur Frame1.
    Donc Form1 sert de boite postale : elle reçoit un message de frame1, lance l'Execute de frame2 qui va renvoyer un message pour mise à jour de frame3...

    Cordialement.
    Thierry

  15. #15
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    salut

    solution avec les evenement

    pour la frame

    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
     
      TFrame1 = class(TFrame)
        Button1: TButton;
        Edit1: TEdit;
        procedure Button1Click(Sender: TObject);
      private
        { private declarations }
        fOnReceiveEvent : TOnReceiveEvent;
        fOnEmitEvent : TOnEmitEvent;
        Procedure EmetMessage(StrMess : String);
     
      public
        { public declarations }
        Procedure OnReceiveEvent(Sender : TObject;var StrMess : String);
        Property OnEmitEvent : TOnEmitEvent read  fOnEmitEvent write fOnEmitEvent;
      end;
     
    implementation
    uses windows;
     
    {$R *.dfm}
     
     
    Procedure TFrame1.EmetMessage(StrMess : String);
    begin
      If assigned(OnEmitEvent) Then
        fOnEmitEvent(self,StrMess);
    end;
     
    Procedure TFrame1.OnReceiveEvent(Sender : TObject;var StrMess : String);
    var
      St : String;
    begin
      If Sender <> Self Then
      begin
         Edit1.Text := StrMess;
      end;
    end;
     
    procedure TFrame1.Button1Click(Sender: TObject);
    var
      St : String;
    begin
      St := (Sender as TControl).Name; // Ici le message
      EmetMessage(St);
    end;
    dans la forme Principale

    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
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    TForm1 = class(TForm)
        ImageList1: TImageList;
        PageControl1: TPageControl;
        TabFrame1: TTabSheet;
        TabFrame2: TTabSheet;
        procedure FormCreate(Sender: TObject);
      private
        fOnEmitEvent    :  TOnEmitEvent;
        fOnReceiveEvent : array of TOnReceiveEvent;
     
        { private declarations }
        FFrame1 : TFrame2;
        FFrame2 : TFrame2;
      Protected
    //      Procedure OnReceiveMainEvent(Sender : TObject;Var StrMess : String);
          Procedure ExecEmitMainEvent(Sender : TObject;Const StrMess : String);
          Function GetOnReceiveEvent(Index : integer) : TOnReceiveEvent;
          Procedure SetOnReceiveEvent(Index : integer;value : TOnReceiveEvent);
      public
        { public declarations }
        Property OnEmitEvent : TOnEmitEvent read  fOnEmitEvent write fOnEmitEvent;
        Property OnReceiveEvent[Index : integer] : TOnReceiveEvent read  GetOnReceiveEvent write SetOnReceiveEvent;
     
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FFrame1 := TFrame1.create(Self);
      FFrame1.Name := 'Test1';
      FFrame1.Parent := TabFrame1;
      FFrame1.OnEmitEvent := ExecEmitMainEvent;
      SetOnReceiveEvent(1,FFrame1.OnReceiveEvent);
     
      FFrame2 := TFrame1.create(Self);
      FFrame2.Name := 'Test2';
      FFrame2.Parent := TabFrame2;
      FFrame2.OnEmitEvent := ExecEmitMainEvent;
      SetOnReceiveEvent(2,FFrame2.OnReceiveEvent);
    //  OnReceiveEvent := FFrame2.OnReceiveEvent;
    end;
     
    Procedure TForm1.ExecEmitMainEvent(Sender : TObject;Const StrMess : String);
    var
      Str : String;
      i : Integer;
    begin
      if assigned(fOnReceiveEvent) Then
       for i := Low(fOnReceiveEvent) to high(fOnReceiveEvent) do
       begin
         Str := StrMess;
         if assigned(fOnReceiveEvent[i]) Then
            fOnReceiveEvent[i](Sender,Str);
      end;
    end;
     
    Function TForm1.GetOnReceiveEvent(Index : integer) : TOnReceiveEvent;
    begin
      Result :=nil;
      if Index < Length(fOnReceiveEvent) Then
         Result := fOnReceiveEvent[Index];
     
    end;
     
    Procedure TForm1.SetOnReceiveEvent(Index : integer;value : TOnReceiveEvent);
    begin
     
      if Index >= Length(fOnReceiveEvent) Then
        SetLength(fOnReceiveEvent,Index+1);
      fOnReceiveEvent[Index] := value
      //fOnReceiveEvent[Index] := @value A voir pour lazaruz
    end;
    la définition des événements

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Type
     
      TOnEmitEvent = Procedure(Sender : TObject ;const StrMess : String) of object;
      TOnReceiveEvent = Procedure(Sender : TObject ;var StrMess : String) of object;
    testé sous delphi j'ai pas lazarus sur place ... je testerai ce soir apres mes autres activité
    je pense qu'il faut ajouter le @

  16. #16
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 142
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 142
    Par défaut
    Le boulot de la soirée, tranquille tranquille :

    Nom : maquette.png
Affichages : 271
Taille : 34,7 Ko

    Ça cause dans tous les sens, je suis juste limité par mon... imagination, un classique en info

  17. #17
    Expert confirmé
    Avatar de anapurna
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    3 491
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 491
    Par défaut
    Salut

    j'ai fait un rapide test sur le tuto, effectivement cela ne semble pas marcher.
    Il faut que je prenne plus de temps pour voir ce qui ne marche effectivement pas.

    Pour les événements, c'est dommage que tu aies abandonné.
    Tu peux faire de grande chose avec ... je m'en sers pour faire avancer un progressbar ou discuter d'une fenêtre à l'autre à l'aide d'un objet centralisateur. Je suis même sûr que tu t'en sers sans le savoir. Il te suffit de comprendre que tu as un événement des Frames -> la form et que la form redistribue à toutes les frames sans distinction... C'est elle qui détermine si elle doit afficher ou non.
    Mais bon si tu as réussi à faire ce que tu voulais, bonne continuation.

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

Discussions similaires

  1. comment utiliser les user Control
    Par lorie dans le forum Windows Presentation Foundation
    Réponses: 14
    Dernier message: 25/11/2010, 12h40
  2. Réponses: 5
    Dernier message: 17/05/2007, 01h19
  3. Réponses: 5
    Dernier message: 11/04/2007, 13h02

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