模态对话框只能屏蔽来自鼠标、键盘的消息,而不能屏蔽其他消息,也即模态对话框会独占用户输入。其实现原理如下:
- 让父窗口失效EnableWindow(pardent,FALSE);
- 建立模态对话框自己的消息循环
- 直至接收关闭消息,消息循环终止并销毁窗口
其中EnableWindow作用是:
Enables or disables mouse and keyboard input to the specified window or control. When input is disabled, the window does not receive input such as mouse clicks and key presses. When input is enabled, the window receives all input.
可以看出EnableWindow会控制是否接收来自键盘、鼠标的消息。
Windows程序中典型的消息循环为:
while(GetMessage( &msg, NULL, 0, 0 )>0) { TranslateMessage(&msg); DispatchMessage(&msg); }
主窗口本身拥有一个消息循环,当创建了一个模态对话框后,程序将进入模态对话框的消息循环直至其退出,接着执行主窗口的消息循环。一个线程中只有一个消息队列,但是可能存在主线程消息循环外的其他局部消息循环,但是他们不会并行执行。因此应用程序发送的消息仍然可以通过模式对话框的消息循环被分配到指定窗口。对于非模式对话框,由于它和主窗口享一个消息循环,所以对主窗口的消息更没有影响。
主消息循环与模态对话框中的局部消息循环之间的关系如下
下面使用MessageBox做一个测试(MessageBox属于模态对话框),测试主窗口弹出MessageBox后对定时器(WM_TIMER消息)的响应情况。Ontimer中对主窗口进行绘图操作:
void CModalAndMessageDlg::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CClientDC dc(this); CRect rect; GetClientRect(&rect); dc.FillSolidRect(rect,RGB(rand()%255,rand()%255,rand()%255)); }
主窗口上按钮响应:
void CModalAndMessageDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 SetTimer(1,1000,NULL); MessageBox(L"Hello!"); }
测试可以发现弹出MessageBox后主窗口的颜色仍然在变化,这就说明WM_TIMER消息仍旧依靠着非模式对话框的消息循环被分配到了主窗口。