|
Вопрос # 2 964/ вопрос открыт / |
|
Доброго времени суток, уважаемые эксперты!
Подскажите, как решить следующую проблему:
Есть расчет, который выполняется в потоке. В нем(алгоритме расчета) куча ShowMessage, которые теперь отрабатывают не нужным образом.
Как можно перехватить сигнал от ShowMessage, чтобы переопределить этот вызов на sendmessage или postmessage?
 |
Вопрос задал: Aндрей (статус: 1-ый класс)
Вопрос отправлен: 2 июля 2009, 10:09
Состояние вопроса: открыт, ответов: 1.
|
Ответ #1. Отвечает эксперт: Вадим К
Здравствуйте, Aндрей!
Есть очень простой и быстрый метод. В классе потока опредеяем метод Showmessage. Теперь поток будет вызывать свой метод вместо функции с юнита dialogs (вроде там она находиться). Само объявление лучше поместить в private часть в виде
procedure ShowMessage(msg:string); и жмем Crtl+Shift+C
теперь уже можно например сделать логирование в файл. Все вызовы в пределах потока будут перехвачены. (если конечно в Вашем коде нет чудес).
Теперь задача номер два - передать строку с потока в основную программу. Поступим самым простым способом.
в коде метода ShowMessage пишем такую реализацию
SendMessage(MainHandle, WM_USER, integer(msg), 0);
MainHandle - это ещё одно поле типа THandle, куда надо передать с главной формы (или какая форма будет принимать сообщения от потока её хендл - просто свойство form1.handle. Это хорошо сделать при инициализации потока).
Теперь прием сообщения в основном окне.
заводим приватный метод формы
procedure MyMessage(var msg:TMessage); message WM_USER;
и жмем снова Crtl+Shift+C.
В процедуре пишем что то вида
memo1.lines.add(string(msg.wparam));
или выводим мессадж.
Использовать PostMessage в данном случае не рекомендованно - postmessage после отправки сообщения продолжает свою работу и строка может поменяться (а мы передаем указатель на строку...)
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 2 июля 2009, 12:21
Оценка за ответ: 5
|
Мини-форум вопроса
Всего сообщений: 7; последнее сообщение — 7 июля 2009, 13:17; участников в обсуждении: 2.
|
Aндрей (статус: 1-ый класс), 6 июля 2009, 16:37 [#1]:
Попробовал сделать так, как Вы описали:
type TSmartThread = class (TThread)
private MainHandle: THandle;
private procedure ShowMessage(const Msg: string);
private function MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
end;
constructor TSmartThread.Create( AForm: TForm; Manager: IStationManager;
ButtonRunCalculate, ButtonBreakCalculate, ButtonFormClose: TControl );
begin
Self.MainHandle := AForm.Handle;
end;
function TSmartThread.MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
begin
SendMessage(Self.MainHandle, WM_USER, integer(msg), 0);
end;
procedure TSmartThread.ShowMessage(const Msg: string);
begin
SendMessage(Self.MainHandle, WM_USER, integer(msg), 0);
end;
//====================== Форма главная
...
private procedure MyMessage(var msg:TMessage); message WM_USER;
...
procedure TFormManager.MyMessage(var msg: TMessage);
var str_msg: string;
begin
str_msg := (string(msg.wparam));
end;
Но при отработке все осталось как было: т.е. в классе, обект которого создается для расчета
function TCalculatorBase.BoilerDescription(const file_path: string; BoilerHeatLoad: Double) : Double;
begin
// ShowMessage('Проверьте, пожалуйста, правильность введенных данных!');
MessageDlg('Проверьте, пожалуйста, правильность введенных данных!',
mtError , [mbOK], 0);
end;
Отрабатывает сначала вывод окна с неправильными размерами.
А в методы, переопределенные в классе TSmartThread, заходит только в MessageDlg и то после вывода окна сообщения, а в ShowMessage не заходит вообще никогда (поэтому в примере кода он закомментирован).
И все равно кидает ошибки: неверный дескриптор и т.п.
Что я делаю неверно?
|
|
Вадим К (статус: Академик), 6 июля 2009, 16:47 [#2]:
странно, должно вообще то заходить. поставьте точку останова на SendMessage(Self.MainHandle, WM_USER, integer(msg), 0); и посмотрите, заходит ли. А также в юните с тредом можно попробовать с списка uses удалить модуль Dialogs (в профилактических целях).
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Aндрей (статус: 1-ый класс), 6 июля 2009, 17:23 [#3]:
В SendMessage не заходит,
Удалил из uses связь с Dialogs - никаких изменений
Может, все таки что-то нагородил. Еще раз опишу, что сделал:
1. В классе-потомке Thread объявил точно такой же как и в Dialogs метод ShowMessage(const Msg: string);
1.1. Добавил в него строку
SendMessage(Self.MainHandle, WM_USER, Integer(Msg), 0);
2. В форме, в которой создаю поток (MainHandle - это Handle этой формы), объявляю
private procedure MyMessage(var msg:TMessage); message WM_USER;
там делаю свою обработку
Все ли верно?
|
|
Вадим К (статус: Академик), 6 июля 2009, 17:49 [#4]:
да всё выглядит правдоподобно. и должно работать.
Точка останова в ShowMessage не срабатывает?
тогда следует попробовать в тестовых целях написать вызов как self.ShowMessage либо либо сделать свое имя. Если и в этом случае не зайдет - выкладывайте полные исходники (кстати, у нас сервис появился, так что можно там. А сюда только ссылку.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Aндрей (статус: 1-ый класс), 7 июля 2009, 10:12 [#5]:
Выдает ошибки:
[DCC Error] GUI.Dialogs.pas(25): E2065 Unsatisfied forward or external declaration: 'TGUIMessageDialogs.ShowMessage'
[DCC Error] GUI.Dialogs.pas(26): E2065 Unsatisfied forward or external declaration: 'TGUIMessageDialogs.MessageDlg'
Что неверно в этом коде??:
unit GUI.Dialogs;
interface
uses
Dialogs;
type
TGUIMessageDialogs = class
private class var FInstance : TGUIMessageDialogs;
public class function getProfile (): TGUIMessageDialogs;
public class procedure FreeProfile();
public class function CreateProfile (MainHandle: THandle): TGUIMessageDialogs;
public class var procedure ShowMessage(const Msg: string);
public class var function MessageDlg (const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
private class var FHandle: THandle;
end;
implementation
uses
Windows,
Messages;
{ TGUIMessageDialogs }
class procedure TGUIMessageDialogs.FreeProfile();
begin
Self.FInstance.Free;
Self.FInstance := nil;
Self.FHandle := 0;
end;
class function TGUIMessageDialogs.GetProfile: TGUIMessageDialogs;
begin
if (Self.FInstance = nil)
or (Self.FHandle = 0 )
then Assert(False, 'TGUIMessageDialogs was not created');
Result := Self.FInstance;
end;
class function TGUIMessageDialogs.MessageDlg(const Msg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Integer): Integer;
begin
SendMessage(TGUIMessageDialogs.FHandle, WM_USER, Integer(Msg), 0);
end;
class procedure TGUIMessageDialogs.ShowMessage(const Msg: string);
begin
SendMessage(TGUIMessageDialogs.FHandle, WM_USER, Integer(Msg), 0);
end;
class function TGUIMessageDialogs.CreateProfile(MainHandle: THandle): TGUIMessageDialogs;
begin
if (Self.FInstance = nil)
then begin
Self.FInstance := TGUIMessageDialogs.Create();
Self.FHandle := MainHandle;
end;
Result := Self.FInstance;
end;
end.
|
|
Вадим К (статус: Академик), 7 июля 2009, 11:39 [#6]:
вы хорошо понимаете суть строки "public class var "?
Судя по коду, слишком много программировали на шарпе. или чем то подобном (java). public и private не обязательно перед каждым объявлением писать. Только делаете код некрасивее. Некрасивый код - ошибкам легче прятаться.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
Aндрей (статус: 1-ый класс), 7 июля 2009, 13:17 [#7]:
Спасибо, с "public class var " разобрался
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|