TForm.ShowModal只是接管消息循环,禁止外部键盘和鼠标输入到别的窗口,但并不封锁其它窗口继续获取消息(比如WM_TIMER消息仍可被发送到别的窗口上)
窗体上放一个TTimer,然后双击输入:
procedure TForm1.Timer1Timer(Sender: TObject);
var
cvs: TCanvas;
Rect: TRect;
Str: string;
begin
cvs := Canvas;
cvs.Font.Style := [fsBold, fsItalic];
cvs.Font.Size := ;
Randomize;
cvs.Font.Color := Random($FFFFFF);
Rect := Screen.DesktopRect;
Str := 'Delphi 绘图';
cvs.TextRect(Rect, , , Str);
end;
再添加一个新窗体和2个按钮:
procedure TForm1.Button1Click(Sender: TObject);
var
s : AnsiString;
begin
s:='dddd';
ShowMessage(s);
end; procedure TForm1.Button2Click(Sender: TObject);
begin
form2.ShowModal;
end;
执行Button1或者Button2之后,Timer1仍在主窗体上不停的绘制文字,这是为什么?
------------------------------------------------------------------------------------
查看ShowModal的内容:
function TCustomForm.ShowModal: Integer;
var
WindowList: Pointer;
SaveFocusCount: Integer;
SaveCursor: TCursor;
SaveCount: Integer;
ActiveWindow: HWnd;
begin
CancelDrag;
if Visible or not Enabled or (fsModal in FFormState) or
(FormStyle = fsMDIChild) then
raise EInvalidOperation.Create(SCannotShowModal);
if GetCapture <> then SendMessage(GetCapture, WM_CANCELMODE, , );
ReleaseCapture;
Application.ModalStarted;
try
Include(FFormState, fsModal);
ActiveWindow := GetActiveWindow;
SaveFocusCount := FocusCount;
Screen.FSaveFocusedList.Insert(, Screen.FFocusedForm);
Screen.FFocusedForm := Self;
SaveCursor := Screen.Cursor;
Screen.Cursor := crDefault;
SaveCount := Screen.FCursorCount;
WindowList := DisableTaskWindows();
try
Show;
try
SendMessage(Handle, CM_ACTIVATE, , );
ModalResult := ;
repeat
Application.HandleMessage; // 该怎么处理还是怎么处理,消息该发送给谁,还是发送给谁
if Application.FTerminate then ModalResult := mrCancel else
if ModalResult <> then CloseModal;
until ModalResult <> ;
Result := ModalResult;
SendMessage(Handle, CM_DEACTIVATE, , );
if GetActiveWindow <> Handle then ActiveWindow := ;
finally
Hide;
end;
finally
if Screen.FCursorCount = SaveCount then
Screen.Cursor := SaveCursor
else Screen.Cursor := crDefault;
EnableTaskWindows(WindowList);
if Screen.FSaveFocusedList.Count > then
begin
Screen.FFocusedForm := Screen.FSaveFocusedList.First;
Screen.FSaveFocusedList.Remove(Screen.FFocusedForm);
end else Screen.FFocusedForm := nil;
if ActiveWindow <> then SetActiveWindow(ActiveWindow);
FocusCount := SaveFocusCount;
Exclude(FFormState, fsModal);
end;
finally
Application.ModalFinished;
end;
end;
再看看Application.HandleMessage的源码:
procedure TApplication.HandleMessage;
var
Msg: TMsg;
begin
if not ProcessMessage(Msg) then Idle(Msg);
end; function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
Handled: Boolean;
begin
Result := False;
if PeekMessage(Msg, , , , PM_REMOVE) then
begin
Result := True;
if Msg.Message <> WM_QUIT then
begin
Handled := False;
if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
if not IsHintMsg(Msg) and not Handled and not IsMDIMsg(Msg) and
not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
begin
TranslateMessage(Msg);
DispatchMessage(Msg); // 仍然正确发送消息
end;
end
else
FTerminate := True;
end;
end;
------------------------------------------------------------------------------------
顺便我还查了一下TTimer的源码,发现它的句柄是借来的,而不是控件所在窗体的句柄:
constructor TTimer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FEnabled := True;
FInterval := ;
FWindowHandle := Classes.AllocateHWnd(WndProc);
end; procedure TTimer.UpdateTimer;
begin
KillTimer(FWindowHandle, );
if (FInterval <> ) and FEnabled and Assigned(FOnTimer) then
if SetTimer(FWindowHandle, , FInterval, nil) = then
raise EOutOfResources.Create(SNoTimers);
end; function AllocateHWnd(Method: TWndMethod): HWND;
var
TempClass: TWndClass;
ClassRegistered: Boolean;
begin
UtilWindowClass.hInstance := HInstance;
ClassRegistered := GetClassInfo(HInstance, UtilWindowClass.lpszClassName,
TempClass);
if not ClassRegistered or (TempClass.lpfnWndProc <> @DefWindowProc) then
begin
if ClassRegistered then
Windows.UnregisterClass(UtilWindowClass.lpszClassName, HInstance);
Windows.RegisterClass(UtilWindowClass);
end;
Result := CreateWindowEx(WS_EX_TOOLWINDOW, UtilWindowClass.lpszClassName,
'', WS_POPUP {!0}, , , , , , , HInstance, nil);
if Assigned(Method) then
SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(Method)));
end;
但是不管怎么说,TTimer的句柄所在的窗口也是也是另外一个窗口,所以不影响结论。
------------------------------------------------------------------------------------
总结:其实这个特性很重要。在许多程序中,模态窗口很重要,因为可以防止许多不必要的操作失误。然而它的运行,却不妨碍程序后台继续运行消息循环从而运行其它任务(如有必要的话),这样的设计,实在是绝美!
TForm.ShowModal只是接管消息循环,禁止外部键盘和鼠标输入到别的窗口,但并不封锁其它窗口继续获取消息(比如WM_TIMER消息仍可被发送到别的窗口上)的更多相关文章
- Android的消息循环机制 Looper Handler类分析
Android的消息循环机制 Looper Handler类分析 Looper类说明 Looper 类用来为一个线程跑一个消息循环. 线程在默认情况下是没有消息循环与之关联的,Thread类在ru ...
- 【转】Android开发实践:自定义带消息循环(Looper)的工作线程
http://ticktick.blog.51cto.com/823160/1565272 上一篇文章提到了Android系统的UI线程是一种带消息循环(Looper)机制的线程,同时Android也 ...
- 深入探讨MFC消息循环和消息泵
首先,应该清楚MFC的消息循环(::GetMessage,::PeekMessage),消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情.在MFC ...
- 什么是消息循环,一个简单的win32程序如何运行?
预备知识 1.什么是句柄? (HANDLE) 在win32编程中有各种句柄,那么什么是句柄呢? #define DECLARE_HANDLE(name) struct name##_ { int un ...
- Android应用程序线程消息循环模型分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6905587 我们知道,Android应用程序是 ...
- Chromium on Android: Android在系统Chromium为了实现主消息循环分析
总结:刚开始接触一个Chromium on Android时间.很好奇Chromium主消息循环是如何整合Android应用. 为Android计划,一旦启动,主线程将具有Java消息层循环处理系统事 ...
- QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 分类: QT2009-10-28 13:33 17695人阅读 评论(13) 收藏 举报 qtapplicationwindowse ...
- Win32 SDK 编程开始, 创建窗口, 消息的处理, 消息循环
Windows SDK 编程的一般步骤为: 1. 注册窗口类, 使用到的结构 WNDCLASSEX, 函数 RegisterClassEx. 2. 创建窗口, 函数 CreateWindowEx. 3 ...
- win32编程中消息循环和WndProc()窗口过程函数
原文地址:https://blog.csdn.net/zxxSsdsd/article/details/45504383 在win32程序的消息循环函数中 while (GetMessage (&a ...
随机推荐
- Android 去掉Activity的跳转动画
startActivity或finish的时候调用一句话即可: overridePendingTransition(0, 0);
- 宽屏手机显示9.png的图片拉伸不均衡
制作的一个.9的背景图片,在一般的480宽的手机上显示没有问题,正常拉伸,用三星的一个宽屏手机测试时,没有完全拉伸,一边拉伸多一点,一边拉伸少一点 决绝办法:就是在制作.9的时候,我在横向拉伸的地方, ...
- itextSharp 对pdf的每个页面添加footer/header
static void SetAllHeaderFooter(string inputPath) { PdfReader reader=new PdfReader(inputPath); PdfSta ...
- C语言指针和数组知识总结(下)
一.数组指针: 数组指针就是一个指针,只不过它指向的是一个数组.可以通过如下方式来定义 typedef int Array[5]; //数组类型 Array* m; //数组定义 还有一种更 ...
- sql:oracle, CURSOR
CursorsYou use a cursor to fetch rows returned by a query. You retrieve the rows into the cursor usi ...
- 基于visual Studio2013解决面试题之0504单链表逆序
题目
- 关于ARM开发板与PC主机的网络设置问题
直观来讲,ARM开发板多数情况下会有条网线与主机相连,所以最重要的一步是保证PC主机与ARM开发板能互通. 互通的意思进一步来讲就是互相能ping通.也就是说在瘟都死的dos下(假设主机是瘟都死系统) ...
- tar打包过滤某个文件及文件夹
ip=ip add|grep eth0|grep -i inet|awk '{print $2}'|cut -d '/' -f 1 cd /data tar -zvcf `echo $ip`_`dat ...
- Unity3D手游-横版ACT游戏完整源代码下载
说明: 这不是武林.这不是江湖,没有道不完的恩怨,没有斩不断的情仇,更没有理不清的烦恼,这是剑的世界,一代剑魁闯入未知世界,将会为这个世界展开什么样的蓝图.让你来创造它的未来,剑魁道天下,一剑斗烛龙! ...
- 【linux】常用网站
Kernel: http://www.kernel.org/ LSB (Linux Standard Base): http://www.linuxbase.org/ ELC(Embedded Lin ...