//必要的话发送WM_KICKIDLE消息给父窗口 if ((dwFlags & MLF_NOKICKIDLE) || !SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)) {
//终止Idle处理 bIdle = FALSE; } }
//第二阶段,发送消息 do {
ASSERT(ContinueModal());
// 若是WM_QUIT消息,则发送该消息到消息队列,返回;否则发送消息。
if (!AfxGetThread()->PumpMessage()) {
AfxPostQuitMessage(0); return -1; }
//必要的话,显示对话框窗口 if (bShowIdle &&
(pMsg->message == 0x118 || pMsg->message == WM_SYSKEYDOWN)) {
ShowWindow(SW_SHOWNORMAL); UpdateWindow(); bShowIdle = FALSE; }
if (!ContinueModal()) goto ExitModal;
//在派发了“正常 ”消息后,重新开始Idle处理 if (AfxGetThread()->IsIdleMessage(pMsg)) {
bIdle = TRUE; lIdleCount = 0; }
} while (::PeekMessage(pMsg, NULL, NULL, NULL, PM_NOREMOVE)); }
ExitModal:
m_nFlags &= ~(WF_MODALLOOP|WF_CONTINUEMODAL); return m_nModalResult; }
BOOL CWnd::ContinueModal() {
return m_nFlags & WF_CONTINUEMODAL; }
void CWnd::EndModalLoop(int nResult)
{
ASSERT(::IsWindow(m_hWnd));
// this result will be returned from CWnd::RunModalLoop m_nModalResult = nResult;
// make sure a message goes through to exit the modal loop
if (m_nFlags & WF_CONTINUEMODAL) {
m_nFlags &= ~WF_CONTINUEMODAL; PostMessage(WM_NULL); } }
和CWinThread::Run的处理过程比较,RunModalLoop也分两个阶段进行处理。不同之处在于,这里不同于Run的Idle处理,RunModalLoop是给父窗口发送WM_ENTERIDLE消息(如果需要的话);另外,当前对话框的父窗口被Disabled,是不接收用户消息的。
RunModalLoop是一个实现自己的消息循环的示例,消息循环的条件是模式化状态没有结束。实现线程自己的消息循环见8.5.6节。
当用户按下按钮“取消”、“确定”时,将导致
RunModalLoop退出消息循环,结束对话框模式状态,并调用::EndDialog关闭窗口。有关关闭对话框的处理如下: void CDialog::EndDialog(int nResult) {
ASSERT(::IsWindow(m_hWnd));
if (m_nFlags & (WF_MODALLOOP|WF_CONTINUEMODAL))
EndModalLoop(nResult); ::EndDialog(m_hWnd, nResult); }
void CDialog::OnOK() {
if (!UpdateData(TRUE)) {
TRACE0(\termination.\\n\
// the UpdateData routine will set focus to correct item return; }
EndDialog(IDOK); }
void CDialog::OnCancel() {
EndDialog(IDCANCEL); }
上述函数OnOk、OnCancle、EndDialog都可以用来关闭对话框窗口。其中:
OnOk首先进行数据交换,获取对话框中各个控制子窗口的数据,然后调用EndDialog结束对话框。 OnCancle直接EndDialog结束对话框。
EndDialog首先修改m_nFlag的值,表示结束模式循环,然后调用::EndDialog关闭对话框窗口。 2. 对话框的数据交换
对话框数据交换指以下两种动作,或者是把内存数据写入对应的控制窗口,或者是从控制窗口读取数据并保存到内存变量中。MFC为了简化这些操作,以CDataExchange类和一些数据交换函数为基础,提供了一套数据交换和校验的机制。
1. 数据交换的方法
首先,定义保存数据的内存变量──给对话框添加成
员变量,每个控制窗口可以对应一个成员变量,或者是控制窗口类型,或者是控制窗口表示的数据的类型。例如,对于对话框的一个编辑控制窗口,可以定义一个CEdit类型的成员变量,或者一个CString类型的成员变量。
其次,覆盖对话框的虚拟函数DoDataExchange,实现数据交换和验证。
ClassWizard可以协助程序员自动地添加成员变量,修改DoDataExchange。例如,一个对话框有两个控制窗口,其中的一个编辑框表示姓名,ID是
IDC_NAME,另一个编辑框表示年龄,ID是IDC_AGE,ClassWizard添加如下的成员变量: // Dialog Data
//{{AFX_DATA(CExDialog) enum { IDD = IDD_DIALOG2 }; CEdit m_name; int m_iAge; //}}AFX_DATA
使用ClassWizard添加成员变量中,一个定义为CEdit,另一个定义为int。这些定义被
“//{{AFX_DATA”和“//}}AFX_DATA”引用,表示是ClassWizard添加的,程序员不必修改它们。 相应的DoDataExchange的实现如下:
void CExDialog::DoDataExchange(CDataExchange* pDX) {