Le boulot de la soirée, tranquille tranquille :
Ça cause dans tous les sens, je suis juste limité par mon... imagination, un classique en info
Le boulot de la soirée, tranquille tranquille :
Ça cause dans tous les sens, je suis juste limité par mon... imagination, un classique en info
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.
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 :
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 :
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...
Je n'ai pê pas tout lu suffisamment attentivement...
La question qui me taraude est la suivante : comment Frame1 sait-il qu'il doit envoyer un message (ou lancer une méthode) de Frame2 ?
Qui doit avoir la réponse à la question ? La fiche principale = l'IHM. Elle seule doit organiser ça, à mon avis.
Donc, à elle d'écouter les messages de ses Frames ou de leur fournir les méthodes à déclencher.
Ceci simplifie sûrement le schéma... Mais je suis pê à côté de la plaque !
Bonjour Yves
(désolé de ne pas avoir répondu + tôt mais quelque choseest[EDIT] était cassé dans la page principale du forum, qui ne remontait plus les dernières entrées -- tout au moins chez moi)
Ah, je crois que tu as une vision trop "machine" et que tu as perdu l'aspect "humain",
C'est moi qui le sais car c'est moi qui code tout ce bouzin !
Un exemple tiré du gros projet (pour lequel j'ai étudié tout ça) :
sur l'onglet 3 il y a un ColorPicker et l'idée était d'envoyer la couleur "pickée", sur <ENTER> (ben vi, tu ne peux plus utiliser la souris sauf à survoler l'écran, dans ce mode), vers l'onglet 1 où se trouve tout un tas de curseurs de réglages (teinte, saturation, etc.)
Et doncla mainform, à la détection d'ENTER', envoie un messagesur <ENTER> dans le FormKeyDown de la mainform je lui fais envoyer un message vers la frame3 où tourne le timer du picker pour
- arrêter le timer
- récupérer la couleur sous la souris
- renvoyer cette couleur au "bureau central de dispatch des messages" (DefaultHandler de la mainform).
Tout ça est fait gentiment par la frame3 à réception du dit message car toutes les frames sont équipées d'un DefaultHandler.
Et lorsque la mainform reçoit le message en retour avec la couleur "pickée", elle se contente de basculer l'ihm sur l'onglet 1 du PageControl et d'assigner la couleur au composant prévu pour.
That's all, folks !
J'étais dessus hier soir et je peux te dire que ça fonctionne tip-top, juste pas se faire des nœuds avec le sens des messages et leurs identifiants (système basé sur le contenu de WParam et LParam, système écrit pas mes soins et c'est moi qui ai décidé que dans la frame3 le WParam à 1 voulait dire "objet Timer" avec LParam à 0 ou 1 pour arrêt-marche, genre pas la peine de faire tourner le timer du picker si l'appli est réduite en barre de tâches et ça, c'est détecté par la mainform qui envoie donc un arrêt au timer).
Simplissime, enfantin, si si, et avec 4 frames le code devient d'une lisibilité reposante : au lieu de scroller dans les 2000 lignes environ d'un seul onglet en v1, tout ça en v2 est réparti sur 4 onglets dans l'EDI (vi, pas confondre les onglets de l'EDI et les onglets de l'application en chantier [lol, on se croirait à Saint-Nazaire quand on y construit un paquebot, ])
Bonne journée, j'y retourne c'est trop bien !
PS : en fait c'est ce que tu disais, et ce que je disais aussi ces derniers jours en parlant de bureau de poste centralisé :
Donc non, tu n'étais pas du tout à côté de la plaque.
Mais je me suis rendu compte d'un truc : en écrivant pour poster une question ou une réponse, ça me permet d'organiser mes pensées pour bien aller au fond des choses (voir les quelques mots barrés plus haut, gardés exprès pour montrer ce que je veux dire).
EDIT : laisse tomber j'ai trouvé !
Merci les Suisses
et ça fonctionne (dans ce sens, de la form vers la frame) juste avec ça :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 procedure TFrame1.MessageReceiver(var msg: TLMessage); begin // http://www.swissdelphicenter.ch/de/showcode.php?id=163 with Msg do Edit1.Text := IntToStr(Msg) + ' '+ IntToStr(WParam) + ' '+ IntToStr(LParam); end;
Le code dans la form étant réduit à sa plus simple expression (mes préférés ) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 const MY_MESSAGE = LM_USER + 2; type TFrame1 = class(TFrame) Button1: TButton; Edit1: TEdit; Panel1: TPanel; procedure Button1Click(Sender: TObject); procedure MessageReceiver(var msg: TLMessage); message MY_MESSAGE; private
/EDIT
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 procedure TForm1.FormCreate(Sender: TObject); begin Frame1 := TFrame1.create(Self); with Frame1 do begin Name := 'FrameTest'; Parent := Form1; Align := alBottom; end; end;
Salut,
je reviens deux minutes là-dessus (moi j'ai passé deux heures à essayer de faire fonctionner un simple bouton, je dois être très mauvais mais je jette l'éponge) car j'aimerais bien comprendre...
Soit une simple Form verte avec un bête bouton, et une simple Frame bleue avec un bête TEdit (sur l'image il y a un bouton en plus, on s'en fiche, il sert dans le sens frame->form) :
Ce que j'aurais aimé, c'est faire transiter un TLMessage au lieu d'une string et voir des choses s'inscrire dans le TEdit, genre
J'ai trituré ton exemple dans tous les sens sans arriver à rien : 9 fois sur 10 ça ne compile pas (je dois être très mauvais) et la fois où ça compile, j'ai beau cliquer sur mon bouton rien ne s'affiche dans le TEdit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Procedure TFrame1.OnReceiveEvent(Sender: TObject; var Msg: TLMessage); begin If Sender <> Self Then with Msg do Edit1.Text:=IntToStr(Msg) +' '+ IntToStr(WParam) +' '+ IntToStr(LParam); end;
Je précise que dans l'autre sens (de la frame vers la form) en utilisant les messages en 10 minutes c'était torché et fonctionnel...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 procedure TForm1.Button1Click(Sender: TObject); begin Frame1.Perform(LM_USER+2, 3, 4); // 2 nombres au pif end;
Création du message et envoi depuis la frame :
et réception dans la form :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 procedure TFrame1.Button1Click(Sender: TObject); var aMess: TLMessage; begin 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); end;
Ah, sous Lazarus il faut l'arrobase sinon pas de compil
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 procedure WndProc(var Message: TLMessage); override; private { private declarations } Frame1: TFrame1; ... 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 Message do ShowMessage(intToStr(WParam) +' '+ PChar(LParam));// "17 This is a message" YAISSE ! LM_USER+2: with Message do ShowMessage(intToStr(WParam) +' '+ intToStr(LParam)); end; end; inherited; // important to forward messages do default handlers end;
Salut
Fais un zip de ton exemple, je regarde cela ce soir et je te dirai où il y a une erreur.
Hé bien c'est très gentil à toi, mais tu n'es pas obligé de te prendre la tête avec ça, hein.
'fin bon, tu vas voir c'est tout en pagaille avec plein de lignes commentées un peu partout, un vrai bronx ; si tu n'avais pas posté vite, toutes les lignes commentées étaient supprimées !
exemple.zip
Salut
J'ai regardé ton code... le truc qui me gêne c'est que tu est obligé d'utiliser l'élément qui doit recevoir l'information...
Cela veut-il dire que les messages ne se propagent pas dans les frames ?
Comment ça, je suis obligé d'utiliser l'élément... ?
C''est quoi le problème ?
J'ai des frames qui font partie intégrante de l'IHM, en gros c'est comme s'il n'y avait pas de frames mais tout dans une seule form. Et s'il n'y a qu'une seule form, une seule IHM, ben oui, l'utilisateur qui est devant l'utilise, je ne comprends pas ce que tu veux dire et pourquoi ça poserait un problème d'utiliser quelque chose qui est prévu pour être utilisé...
C'est comme si tu montais dans une bagnole et là, "ah ben merde alors, elle roule" ! Ben oui, elle est prévue pour ça.
Ben oui ils se propagent dans la frame, ou alors chez toi ça ne fonctionne pas ? Chez moi quand je clique sur le bouton en haut à gauche faisant partie de la form, ça écrit dans le TEdit en bas qui fait partie de la frame.
Là encore je ne comprends pas ce que tu dis, désolé.
Salut
Je pense que l'on ne parle pas le même langage.
Tu nommes bien la frame1 pour lui envoyer le message, c'est l'équivalent de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 procedure TForm1.Button1Click(Sender: TObject); begin Frame1.Perform(LM_USER+2, 2, 3); end;à chaque frame et chaque destinataire ; il va donc falloir les désigner.
Code : Sélectionner tout - Visualiser dans une fenêtre à part sendMessage(frame1.handle,...
Exactement de la même manière que si tu écris à tes potes Pierre Paul et Jacques : tu mets leur nom et leur adresse sur les enveloppes qui leur sont destinées, je ne vois pas où est le problème...
Par exemple, dans la frame du ColorPick, voilà ce qui se passe à la réception des messages en provenance de la MainForm :Sur 1 le TimerPicker est activé ou pas, sur 2 c'est la case à cocher qui indique son état, sur 3 on active le code de capture de couleur qui, pour des raisons historiques est écrit dans la procédure d'un bouton.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 procedure TfrmColorPick.DefaultHandler(var Msg); begin // source : touches p, v, ENTER depuis MainForm if (TLMessage(Msg).Msg = LM_FROMOFFICE) then case Integer(TLMessage(Msg).WParam) of 1: TimerPicker.Enabled := boolean(Integer(TLMessage(Msg).LParam)); 2: ckbxVisible.Checked := boolean(Integer(TLMessage(Msg).LParam)); 3: btnCaptureClick(Self); end; end;
Et tout fonctionne impeccablement.
Et pour en revenir à la maquette de cet après-midi, une fois la solution trouvée, je peux facilement l'adapter à cette organisation.
Et si je voulais écrire à tous les destinataires (toutes les frames), j'ai prévu un message LM_GENERAL que tous les DefaultHandler devraient pouvoir traiter (si je mets le code, mais je ne pense pas que cette appli en ait besoin -- en tout cas, la maquette présentée il y a quelques jours l'avait en démo [case à cocher "toutes" dans le post "le boulot de la soirée"])
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 :
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
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;
cf :
Ici :
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;
Paf dans les dents, un bon gros SIGSEGV
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 // pas vu de diff // aText: string = 'This is a message';
Dans :
Idem SIGSEGV et idem avec postmessage
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;
"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
Bonjour,
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 )
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...
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.
Salut JP.
Je vais te répondre ici (ou tenter de te répondre) pour donner un exemple sous Lazarus.j'ai posé là une question assez générique...
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.
Bouton gauche sur la fiche.
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;
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 :
Pour les messages user, je préfère utiliser une procédure spécifique (question de goût).
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;
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.
Je ne sais pas si j'ai été très clair, alors n'hésite pas...
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;
Amicalement
Thierry
Salut Thierry,
Très clair à 99 % !
Le pourcent restant concerne ce que j'ai cité, et particulièrement la présence de ce inherited dans cette procédure censée ne travailler (d'après ce que tu écris en haut de citation et que j'ai mis en gras) que sur les message user.
En toute logique ce inherited ne va rien transmettre puisque tout aura été géré avant, ou alors je n'ai rien compris ?
En toute logique, il ne traitera rien.
Mais si on dérive une fiche d'une autre, son inherited appellera le DefaultHandler de l'ancêtre.
On peut considérer que c'est une bonne pratique de mettre inherited, qu'il serve ou pas, à condition de ne pas le mettre s'il ne fallait pas (cad si on doit remplacer complètement le comportement ancestral dans un descendant, et ne pas le déclencher) : si on ajoute un comportement, il intervient après ou avant le traitement ancestral, selon la position du inherited. Si on veut zapper un comportement, il faut ignorer celui de l'ancêtre, donc omettre le inherited).
Salut tourlourou.
Tu as raison, inherited n'est pas obligatoire dans la procédure DefaultHandler.
Salut JP.
Petites précisions :
je n'ai jamais dit que DefaultHandler ne travaillait que sur les messages user. Tu as des messages système qui n'ont pas de traitement défini. Par exemple, des messages comme WM_NCHITTEST, WM_NOTIFY aboutissent à DefaultHandler, tandis que des messages comme WM_SIZE, WM_LBUTTONDOWN disposent de leur traitement (réception du message par le composant qui le "traduit" en événement (OnResize, OnMouseDown...).
Pour l'envoi d'un message, si on utilise Perform ou SendMessage (PostMessage) : le message est toujours analysé en premier lieu dans la procédure WndProc.
Par contre, si on utilise Dispatch, c'est la procédure DefaultHandler qui est directement appelée. Exemple :
Je n'utiliserais la méthode Dispatch que pour les messages user.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 procedure TForm1.Button1Click(Sender: TObject); var Msg: TMessage; begin Msg.msg:= MYMESSAGE; Msg.wParam:= 123; Form1.Dispatch(Msg); end;
Amicalement
Thierry
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager