Lorsque vous rédigez des programmes, vous rencontrez toujours des problèmes avec la communication entre le formulaire (TForm) et le message Thread (TTHREAD). Ce qui est ennuyeux, c'est que le formulaire ne peut pas envoyer de messages au thread (Tthread) (le thread n'a pas de poignée de fenêtre). Après plusieurs jours de dur labeur, j'ai trouvé deux solutions et les ai emmenées discuter avec vous.
D'abord. Nous savons que la bibliothèque de classe MFC dans VC ++ a un traitement des messages encapsulé (BeginMessage, EndMessage). La table de mappage (le traitement des messages est essentiellement un appel à une méthode ou un processus), plus un mécanisme de distribution de messages pour réaliser la réception et la transmission des messages <voir VC ++ Technical Insider> pour plus de détails. Nous avons donc juste besoin d'établir une table de mappage de messages pour le thread et d'établir un mécanisme de distribution de message correspondant. Cela vous permet de traiter les messages envoyés par le formulaire au fil. Le code suivant est une classe qui met en œuvre le tableau de mappage de messages et la distribution des messages (voir <../ conception de traitement des messages (thread) 1 / messagehandle.pas> pour plus de détails)
Unité MessageHandle;
interface
utilise des messages, des classes, des systèmes, des boîtes de dialogue;
const pmsg_base = $ be00;
PMSG_NUM = 200;
{** Classe de traitement des messages personnalisé
*; Function = créer une table de message personnalisée et un processus entre les threads
* et messages personnalisés avec le formulaire principal (macro)
*}
// Poignée de traitement des messages
TMessageHandle = procédure (message var: tMessage) de l'objet;
Tpdispatcher = classe (tobject)
Privé
// Tableau correspondant à message (ID de message est un indice du tableau);
MessageHandles: tableau de TMessageHandle;
// Obtenez l'ID de tableau de l'ID de message
function getIndexFrommsgid (constaMSSageId: Cardinal): entier;
publique
constructeur créé;
destructeur détruire;
//Envoyer un message
Procédure SendMessage (message VAR: TMessage);
// Ajouter un message personnalisé à la table correspondante du message;
Procédure AddHandle (constaMSSAGEID: Cardinal; AMESSAGEHANDLE: TMessageHandle);
fin;
//
Mise en œuvre
{TPDispatcher}
constructeur tpdispatcher.create;
var i: entier;
Commencer
SetLength (MessageHandles, PMSG_NUM);
// Initialisez la file d'attente de messages;
pour i: = 0 à pred (pmsg_num) faire
MessageHandles [i]: = nil;
fin;
destructor tpdispatcher.destroy;
Commencer
{Release Message Correspondence Table
Freeandnil (MessageHandles);
fin;
Procédure tpdispatcher.addhandle (constaMessageId: Cardinal;
AmessageHandle: TMessageHandle);
var tid: entier;
Commencer
Tid: = getIndexFrommsgid (AMESSAGEID);
Affirmer ((Tid> 0) ou (Tid <Pred (pmsg_num)));
Affirmer (attribué (amessageHandle));
MessageHandles [TID]: = AMESSAGEHANDLE;
fin;
fonction tpdispatcher.getIndexFrommsgid (constaMessageId: cardinal): entier;
Commencer
Résultat: = AMESSAGEID - PMSG_BASE;
fin;
procédure tpdispatcher.sendMessage (message var: tMessage);
var tid: entier;
TMSGHANDLE: TMessageHandle;
Commencer
Tid: = getIndexFrommsgid (message.msg);
Affirmer ((Tid> 0) ou (Tid <Pred (pmsg_num)));
tmSGHandle: = MessageHandles [TID];
si elle est affectée (tmsghandle) alors
tmsghandle (message);
fin;
Nous devons maintenant enregistrer un message personnalisé, puis utiliser la classe de distribution de messages (TPDispatcher) pour traiter les messages de threads. Le code est le suivant <Voir ../ Conception de traitement des messages (Thread) 1 / Test / Unit1.pas> Pour plus de détails:
Unité unité 1
const
{Message de thread à long terme personnalisé}
My_Message2 = pmsg_base + 02;
taper
Tform1 = classe (tform)
Addmsglist: tbutton;
Sendthehead: Tbutton;
Sendform: TBUTTON;
Envoyer autre: Tbutton;
Procédure SendTheAdClick (expéditeur: tobject);
Procédure FormCreate (expéditeur: tobject);
Procédure FormDestroy (expéditeur: tobject);
Privé
Fdispatcher: tpdispatcher;
Fhandle: tphandler;
FTHREAD: TPTHREAD;
publique
{Déclarations publiques}
fin;
var
FORM1: TFORM1;
Mise en œuvre
{$ R * .dfm}
Procédure TForm1.SendTheadClick (expéditeur: tobject);
Var Assage: Tmessage;
AMESSAGE.MSG: = MY_MESSAGE2;
AMESSAGE.WPARAM: = 1;
Fdispatcher.sendMessage (AMESSAGE);
fin;
fin;
Procédure TForm1.FormCreate (Sender: Tobject);
Commencer
{Créer une classe de table de carte de message}
Fdispatcher: = tpdispatcher.create;
Fhandle: = tphandler.create;
{créer du thread}
Fthread: = tpthread.create (false);
{Ajouter un message à la table de mappage}
Fdispatcher.addhandle (my_message2, fthread.domessage);
fin;
Procédure tform1.formDestroy (expéditeur: tobject);
var i: entier;
Commencer
Freeandnil (fdispatcher);
Freeandnil (fhandle);
pour i: = 0 à 3 faire
Freeandnil (fthread [i]);
fin;
deuxième. Une fenêtre peut gérer les messages car il a une poignée de fenêtre. Pour que le thread gère les messages, nous pouvons ajouter une poignée de fenêtre au thread de la classe de fenêtre correspondante. (Le code source est dans <../ conception de traitement des messages (thread) 2 / pthread.pas>)
unité pthread;
interface
Utilise des classes, des systèmes, des fenêtres, des messages, des boîtes de dialogue;
const my_message1 = $ bd00 + 01;
Taper
{** Classe de threads de traitement des messages
*; Function = Ajouter une capacité de traitement de thread,
*}
Tpmsgthread = class (tthread)
Privé
// poignée de fenêtre
Fwndhandle: hwnd;
// Informations sur les données de fenêtre
Fwndclass: wndclass;
// Pointer vers la fonction de rappel de fenêtre
FobjectInstance: pointeur;
// Initialiser les données de fenêtre
procédure initwnd;
// Créer une fenêtre cachée
procédure createwnd;
// Enregistrer la fenêtre cachée
Procédure Registwnd;
procédure destroywnd;
// Fonction de rappel de fenêtre
Procédure PWNDDProc (Message VAR: TMESSAGE);
protégé
procédure d'exécution;
Procédure Doterminate;
publique
Conclusion Create (Créer, Boolean);
propriété wndhandle: hwnd read fwndhandle write fwndhandle;
fin;
Mise en œuvre
const wnd_name = 'py20';
{Tpmsgthread}
constructeur tpmsgthread.create (CreateSpened: booléen);
Commencer
Hérité de création (Création de personnes réunies);
FwndHandle: = Integer (nil);
Initwnd;
Registwnd;
Createwnd;
fin;
procédure tpmsgthread.createwnd;
Commencer
if (wndhandle = entier (nil)) alors
Wndhandle: = createWindow (fwndclass.lpszclassname, fwndclass.lpszclassname,
Ws_popup ou ws_caption ou ws_clipsibrings ou ws_sysmenu
ou ws_minimizebox,
GetSystemMetrics (SM_CXSCREEN) Div 2,
GetSystemMetrics (SM_CYSCREEN) Div 2,
0, 0, 0, 0, fwndclass.hinstance, nil);
// remplacer la fonction de rappel de fenêtre
SetWindowlong (WndHandle, gwl_wndproc, longInt (fobjectInstance));
fin;
procédure tpmsgthread.destroywnd;
Commencer
UnregisterClass (fwndclass.lpszclassName, fwndclass.hinstance);
Destroywindow (wndhandle);
fin;
procédure tpmsgthread.dotermiate;
Commencer
hérité;
Destroywnd;
fin;
procédure tpmsgthread.exécute;
Commencer
fin;
procédure tpmsgthread.initwnd;
Commencer
Fwndclass.lpszClassName: = pChar (wnd_name);
Fwndclass.hinstance: = manche;
Fwndclass.lpfnwndproc: = @defwindowProc;
fin;
Procédure tpmsgthread.pwndproc (message var: tMessage);
Commencer
fin;
procédure tpmsgthread.registwnd;
Commencer
FObjectInstance: = Classes.MakeObjectInstance (pwndProc);
if (fwndclass.hinstance <> entier (nil)) puis
RegisterClass (fwndclass);
fin;