我启用了TTimer
,并且应该永久运行,直到用户停止它为止。但是,它不起作用。在OnTimer
事件中,它会在几毫秒内反复处理窗口消息。
例如,这是我的代码片段。
procedure TDXCommDlg.Timer2Timer(Sender: TObject);
begin
inherited;
if Scanning then
begin
Timer1.Enabled := false;
Timer2.Enabled := false;
while not PostMessage(Handle,WM_USER + 10,1234,5678) do;
Timer1.Enabled := true;
end;
end;
这是怎么回事。当TTimer启用并运行时,您拖动应用程序的任何窗口或单击下拉菜单,TTimer事件完全停止工作,即使我已在代码的其他部分采取预防措施以防止这种情况发生。但是,它似乎并没有帮助。
重新启动OnTimer
事件的唯一方法是由用户通过TButton事件停止并重新启动Timer。
在使用Delphi 7编译的Windows XP下,相同的代码或程序可以正常工作。目前,我正在使用Windows 7和Delphi 2010来重建我的系统。
我会尽力为您提供更多信息。我正在研究的是受版权保护的软件。
有一个名为HandleMsg的用户定义过程。它实际上处理串口消息。 HandleMsg设置为Application事件onMessage;
Application.onMessage:= HandleMsg();
PostMessage与应用程序的onMessage事件相关联。
每当调用PostMessage时,它都会触发onMessage事件,该事件设置为HandleMsg()。
这里有更多我的代码:
procedure TDXCommDlg.HandleMsg(var
Msg: TMsg; var Handled: Boolean);
begin
Handled := false;
case Msg.message of
WM_USER + 10:
begin
if (Msg.wParam = 1111) and (Msg.lParam = 2222) then
begin
SendLanMessage;
Handled := true;
end
else if (Msg.wParam = 1234) and (Msg.lParam = 5678) then
begin
SendMessage;
Handled := true;
end
else
begin
if (Msg.wParam = 4321) then
begin
MainFrm.CloseWindow(TViewFrm(Msg.lParam).WinCap);
end;
end;
end;
end; { case } end;
HandleMsg()响应PostMessage。如果我错了,请纠正我。
答案 0 :(得分:6)
在这两种情况下(开始调整大小/移动窗口或打开菜单),如果标题和系统菜单存在并点击,则从TApplication.ProcessMessage
调度的最后一条消息为WM_NCLBUTTONDOWN
(或WM_NCRBUTTONDOWN
在标题..或WM_RBUTTONUP
如果打开上下文菜单等...)。共同点是他们正在开始一个模态消息循环。
例如,以下内容来自WM_ENTERSIZEMOVE
文档:
发送WM_ENTERSIZEMOVE消息 进入后一次到窗口 移动或调整模态循环。 [....]操作完成时 DefWindowProc返回。
启动模态消息循环后,HandleMessage
中的TApplication.Run
调用将不会返回,直到相关窗口的DefWindowProc
返回为止(例如,在WM_NCLBUTTONDOWN
情况下,调度消息将导致WM_SYSCOMMAND
被发送到窗口,该窗口将启动模态消息循环,并且在移动/调整大小完成之前不会返回。因此,您将无法在OnMessage
中调用的此期间使用应用程序的TApplication.ProcessMessage
处理程序。
您的解决方案很简单。而不是使用OnMessage
处理程序,使用表单的消息处理程序处理消息:
const
WMUSER_10 = WM_USER + 10;
type
TForm1 = class(TForm)
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
private
procedure WmUser10(var Msg: TMsg); message WMUSER_10;
public
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
PostMessage(Handle, WMUSER_10, 1234, 5678);
end;
procedure TForm1.WmUser10(var Msg: TMsg);
begin
//
end;
或者,将您的代码置于OnTimer
事件中,因为WM_TIMER
本身已发布。
答案 1 :(得分:0)
这是可以预料的。 Windows计时器基于消息队列标志,它是优先级最低的事件。当您开始调整窗口大小时,主应用程序事件队列中的计时器标志将停止处理,计时器将停止。你无能为力。要清楚,普通消息仍然有效,但计时器停止。这很容易测试。
现在,要解决此问题,您可以发送自己的WM_USER消息,这应该通过,或者更好的解决方案是使用线程执行关键操作并使用计时器从线程更新的信息更新UI。然后,当用户调整窗口大小时,会出现UI暂停,但操作仍在继续。