При написании программ вы всегда сталкиваетесь с проблемами с сообщением между формой (Tform) и сообщением потока (Tthread). Что раздражает, так это то, что форма не может отправлять сообщения в поток (tthread) (поток не имеет ручки окна). После нескольких дней тяжелой работы я придумал два решения и взял их, чтобы обсудить с вами.
Первый. Мы знаем, что библиотека классов MFC в VC ++ имеет инкапсулированную обработку сообщений (BeginMessage, EndMessage) Таблица отображения (обработка сообщений по сути является вызовом метода или процесса), а также механизм распределения сообщений для реализации приема и передачи сообщений <см. VC ++ Technical Insider> для получения подробной информации. Таким образом, нам просто нужно установить таблицу отображения сообщений для потока и установить соответствующий механизм распределения сообщений. Это позволяет обрабатывать сообщения, отправляемые формой в поток. Следующий код - это класс, который реализует таблицу сопоставления сообщений и распределение сообщений (см. <../ Проектирование обработки сообщений (поток) 1/messageHandle.pas> Для получения подробной информации)
Unit MessageHandle;
интерфейс
Использует сообщения, классы, Sysutils, Dialogs;
const pmsg_base = $ be00; // Пользовательский базовый адрес сообщений;
PMSG_NUM = 200; // Размер таблицы сообщений;
{** Класс обработки пользовательских сообщений
*; Function = создать пользовательскую таблицу сообщений и процесс между потоками
* и пользовательские сообщения с основной формой (макрос)
*}
// Ручка обработки сообщений
Tmessagehandle = процедура (var Сообщение: tmessage) объекта;
Tpdispatcher = class (tobject)
Частный
// Сообщение о соответствующей таблице (идентификатор сообщения является подписанием массива);
MessageHandles: массив TmessageHandle;
// получить идентификатор массива от идентификатора сообщения
function getIndexfrommsgid (const amessageid: cardinal): целое число;
публичный
конструктор создать;
разрушитель разрушил;
// Отправить сообщение
Процедура SendMessage (VAR: Tmessage);
// Добавить пользовательское сообщение в соответствующую таблицу сообщения;
процедура addHandle (const amessageid: cardinal; amessagehandle: tmessagehandle);
конец;
//
Выполнение
{Tpdispatcher}
конструктор tpdispatcher.create;
var i: целое число;
Начинать
SetLength (MessageHandles, PMSG_NUM);
// Инициализировать очередь сообщения;
для i: = 0 до Pred (pmsg_num)
MessageHandles [i]: = nil;
конец;
деструктор tpdispatcher.destroy;
Начинать
{Таблица переписки сообщений}
Freeandnil (MessageHandles);
конец;
Процедура tpdispatcher.addhandle (const amessageid: cardinal;
Amessagehandle: tmessagehandle);
var tid: целое число;
Начинать
tid: = getIndexFrommsgid (amessageid);
Assert ((tid> 0) или (tid <pred (pmsg_num)));
Assert (назначен (AmessageHandle));
MessageHandles [TID]: = AmessageHandle;
конец;
function tpdispatcher.getindexfrommsgid (const amessageid: cardinal): целое число;
Начинать
Результат: = amessageid - pmsg_base;
конец;
Процедура tpdispatcher.sendmessage (var Сообщение: tmessage);
var tid: целое число;
tmsghandle: tmessagehandle;
Начинать
tid: = getIndexfrommsgid (message.msg);
Assert ((tid> 0) или (tid <pred (pmsg_num)));
tmsghandle: = messageHandles [tid];
Если назначено (tmsghandle), тогда
tmsghandle (сообщение);
конец;
Теперь нам нужно только зарегистрировать пользовательское сообщение, а затем использовать класс распределения сообщений (TPDispatcher) для обработки сообщений потоков. Код следующим образом <см. ../ Конструкция обработки сообщений (поток) 1/test/unit1.pas> Для получения подробной информации:
Единица 1
констант
{Пользовательское долгосрочное сообщение потока}
My_message2 = pmsg_base + 02;
тип
Tform1 = class (tform)
Addmsglist: tbutton;
Sendthehead: Tbutton;
Sendform: Tbutton;
Sendother: Tbutton;
Процедура SendTheadClick (отправитель: Tobject);
Процедура FormCreate (отправитель: Tobject);
процедура FormDestroy (отправитель: Tobject);
Частный
FDispatcher: TPDispatcher;
Fhandle: Tphandler;
Fthread: Tpthread;
публичный
{Публичные объявления}
конец;
вар
Форма1: tform1;
Выполнение
{$ R *.dfm}
Процедура tform1.sendtheadclick (отправитель: tobject);
VAR AMESSAGE: TMESSAGE;
amessage.msg: = my_message2;
amessage.wparam: = 1;
Fdispatcher.sendmessage (amessage);
конец;
конец;
Процедура tform1.formcreate (отправитель: tobject);
Начинать
{Создать класс таблицы карт сообщений}
Fdispatcher: = tpdispatcher.create;
Fhandle: = tphandler.create;
{создать поток}
Fthread: = tpthread.create (false);
{Добавить сообщение в таблицу сопоставления}
Fdispatcher.addhandle (my_message2, fthread.domessage);
конец;
Процедура tform1.formDestroy (отправитель: tobject);
var i: целое число;
Начинать
Freeandnil (fdispatcher);
Freeandnil (fhandle);
для i: = 0 до 3
Freeandnil (fthread [i]);
конец;
второй. Окно может обрабатывать сообщения, потому что у него есть ручка окон. Для того, чтобы поток обрабатывал сообщения, мы можем добавить ручку с окном в потоку соответствующего класса окна. (Исходный код находится в <../ Конструкция обработки сообщений (поток) 2 / pthread.pas>)
единица Pthread;
интерфейс
использует классы, Sysutils, Windows, сообщения, диалоги;
const my_message1 = $ bd00 + 01;
Тип
{** Класс потоков обработки сообщений
*; Function = добавить возможности обработки потока,
*}
Tpmsgthread = class (tthread)
Частный
// оконная ручка
Fwndhandle: hwnd;
// Информация о данных окна
Fwndclass: wndclass;
// Указатель на функцию обратного вызова окна
FobjectInstance: указатель;
// Инициализировать данные окна
процедура initwnd;
// Создать скрытое окно
процедура CreateWnd;
// зарегистрировать скрытое окно
Процедура Registwnd;
Процедура DroustWnd;
// Функция обратного вызова окон
Процедура pwndproc (var Сообщение: tmessage);
защищен
процедура выполнить;
процедура DoterMinate;
публичный
конструктор Create (CreateSusped: Boolean);
Собственность Wndhandle: Hwnd читать fwndhandle написать fwndhandle;
конец;
Выполнение
const wnd_name = 'py20';
{Tpmsgthread}
конструктор tpmsgthread.create (CreateSusped: Boolean);
Начинать
унаследованное создание (CreateSusped);
Fwndhandle: = integer (nil);
Initwnd;
Registwnd;
Createwnd;
конец;
Процедура tpmsgthread.createwnd;
Начинать
if (wndhandle = integer (nil))
Wndhandle: = createwindow (fwndclass.lpszclassname, fwndclass.lpszclassname,
Ws_popup или ws_caption или ws_clipsiblings или ws_sysmenu
или ws_minimizebox,
GetSystemmetrics (SM_CXSCREEN) DIV 2,
GetSystemmetrics (SM_CYSCREEN) DIV 2,
0, 0, 0, 0, fwndclass.hinstance, nil);
// Заменить функцию обратного вызова окон
SetWindowlong (wndhandle, gwl_wndproc, longint (fobjectinstance));
конец;
Процедура tpmsgthread.destroywnd;
Начинать
Unregisterclass (fwndclass.lpszclassname, fwndclass.hinstance);
DissultWindow (wndhandle);
конец;
Процедура tpmsgthread.doterminate;
Начинать
унаследован;
Уничтожить;
конец;
Процедура tpmsgthread.execute;
Начинать
конец;
Процедура tpmsgthread.initwnd;
Начинать
Fwndclass.lpszclassname: = pchar (wnd_name);
Fwndclass.hinstance: = handle;
Fwndclass.lpfnwndproc: = @defwindowproc;
конец;
Процедура tpmsgthread.pwndproc (var message: tmessage);
Начинать
конец;
Процедура tpmsgthread.registwnd;
Начинать
FobjectInstance: = class.makeObjectInstance (pwndproc);
if (fwndclass.hinstance <> integer (nil))
Registerclass (fwndclass);
конец;