对话框和对话框类CDialogWord文件下载.docx
《对话框和对话框类CDialogWord文件下载.docx》由会员分享,可在线阅读,更多相关《对话框和对话框类CDialogWord文件下载.docx(40页珍藏版)》请在冰豆网上搜索。
1无模式对话框
一个无模式对话框是一个有系统菜单、标题栏、边线等的弹出式窗口。
在创建对话框模板时指定WS_POPUP、WS_CAPTION、WS_BORDER和WS_SYSMENU风格。
如果没有指定WS_VISIBLE风格,无模式对话框不会自动地显示出来。
一个无模式对话框既不会禁止所属窗口,也不会给它发送消息。
当创建一个模式对话框时,Windows使它成为活动窗口,但用户或者程序可以随时改变和设置活动窗口。
如果对话框失去激活,那么即使所属窗口是活动的,在Z轴顺序上,它仍然在所属窗口之上。
应用程序负责获取和派发输入消息给对话框。
大部分应用程序使用主消息循环来处理,但是为了用户可以使用键盘在控制窗口之间移动或者选择控制窗口,应用程序应该调用:
IsDialogMessage函数。
这里,顺便解释:
虽然该函数是为无模式对话框设计的,但是任何包含了控制子窗口的窗口都可以调用它,用来实现类似于对话框的键盘选择操作。
当:
IsDialogMessage处理一个消息时,它检查键盘消息并把它们转换成相应对话框的选择命令。
例如,当Tab键被压下时,下一个或下一组控制被选中,当DownArrow键按下后,一组控制中的下一个控制被选择。
IsDialogMessage完成了所有必要的消息转换和消息派发,所以该函数处理的消息一定不要传递给TranslateMessage和DispatchMessage处理。
一个无模式对话框不能像模式对话框那样返回一个值给应用程序。
但是对话框过程可以使用:
SendMessage给所属窗口传递信息。
在应用程序结束之前,它必须销毁所有的无模式对话框。
使用:
DestroyWindow销毁一个无模式对话框,不是使用:
EndDiaLog。
一般来说,对话框过程响应用户输入,如用户选择了“取消”按钮,则调用:
DestroyWindow;
如果用户没有有关动作,则应用程序必须调用:
DestroyWindow。
对话框的MFC实现
在MFC中,对话框窗口的功能主要由CWnd和CDialog两个类实现。
CDialog的设计和实现
MFC通过CDialog来封装对话框的功能。
CDialog从CWnd继承了窗口类的功能(包括CWnd实现的有关功能),并添加了新的成员变量和函数来处理对话框。
CDialog的成员变量
CDialog的成员变量有:
protected:
UINTm_nIDHelp;
//HelpID(0fornone,seeHID_BASE_RESOURCE)
LPCTSTRm_lpszTemplateName;
//nameorMAKEINTRESOURCE
HGLOBALm_hDialogTemplate;
//indirect(m_lpDialogTemplate==NULL)
//indirectif(m_lpszTemplateName==NULL)
LPCDLGTEMPLATEm_lpDialogTemplate;
void*m_lpDialogInit;
//DLGINITresourcedata
CWnd*m_pParentWnd;
//parent/ownerwindow
HWNDm_hWndTop;
//toplevelparentwindow(maybedisabled)
成员变量保存了创建对话框的模板资源、对话框父窗口对象、顶层窗口句柄等信息。
三个关于模板资源的成员变量m_lpszTemplateName、m_hDialogTemplate、m_lpDialogTemplate对应了三种模板资源,但在创建对话框时,只要一个模板资源就可以了,可以使用其中的任意一类。
1CDialog的成员函数:
2构造函数:
CDialog(LPCTSTRlpszTemplateName,CWnd*pParentWnd=NULL);
CDialog(UINTnIDTemplate,CWnd*pParentWnd=NULL);
CDialog();
CDialog重载了三个构造函数。
其中,第三个是缺省构造函数;
第一个和第二个构造函数从指定的对话框模板资源创建,pParentWnd指定了父窗口或所属窗口,若空则设置父窗口为应用程序主窗口。
3初始化函数
BOOLCreate(LPCTSTRlpszTemplateName,CWnd*pParentWnd=NULL);
BOOLCreate(UINTnIDTemplate,CWnd*pParentWnd=NULL);
BOOLCreateIndirect(LPCDLGTEMPLATElpDialogTemplate,CWnd*pParentWnd=NULL);
BOOLCreateIndirect(HGLOBALhDialogTemplate,CWnd*pParentWnd=NULL);
BOOLInitModalIndirect(LPCDLGTEMPLATElpDialogTemplate,CWnd*pParentWnd=NULL);
BOOLInitModalIndirect(HGLOBALhDialogTemplate,CWnd*pParentWnd=NULL);
Create用来根据模板创建无模式对话框;
CreateInDirect用来根据内存中的模板创建无模式对话框;
InitModalIndirect用来根据内存中的模板创建模式对话框。
它们都提供了两个重载版本。
4对话框操作函数
voidMapDialogRect(LPRECTlpRect)const;
voidNextDlgCtrl()const;
voidPrevDlgCtrl()const;
voidGotoDlgCtrl(CWnd*pWndCtrl);
voidSetDefID(UINTnID);
voidSetHelpID(UINTnIDR);
voidEndDialog(intnResult);
5虚拟函数
virtualintDoModal();
virtualBOOLOnInitDialog();
virtualvoidOnSetFont(CFont*pFont);
virtualvoidOnOK();
virtualvoidOnCancel();
MFC模式对话框的实现
从前面的介绍可以知道,Win32SDK编程下的模式对话框使用了Windows提供给对话框窗口的窗口过程和自己的对话框过程,对话框过程将被窗口过程调用。
但在MFC下,所有的窗口类都使用了同一个窗口过程,CDialog也不例外。
CDialog对象在创建Windows对话框时,采用了类似于CWnd的创建函数过程,采用子类化的手段将Windows提供给对话框的窗口过程取代为AfxWndProc或者AfxBaseWndProc,同时提供了对话框过程AfxDlgProc。
那么,这些“过程”是如何实现或者协调的呢?
下文将予以分析。
MFC对话框过程
MFC对话框过程AfxDlgProc的原型和实现如下:
BOOLCALLBACKAfxDlgProc(HWNDhWnd,
UINTmessage,PARAM,LPARAM)
{
if(message==WM_INITDIALOG)
//处理WM_INITDIALOG消息
CDialog*pDlg=DYNAMIC_DOWNCAST(CDialog,
CWnd:
FromHandlePermanent(hWnd));
if(pDlg!
=NULL)
returnpDlg->
OnInitDialog();
else
return1;
}
return0;
由上可以看出,MFC的对话框函数AfxDlgProc仅处理消息WM_INITDIALOG,其他都留给对话框窗口过程处理。
因此,它不同于SDK编程的对话框过程。
程序员在SDK的对话框过程处理消息和事件,实现自己的对话框功能。
AfxDlgProc处理WM_INITDIALOG消息时调用虚拟函数OnInitDialog,给程序员一个机会处理对话框的初始化。
模式对话框窗口过程
本小节讨论对话框的窗口过程。
AfxWndProc是所有的MFC窗口类使用的窗口过程,它取代了模式对话框原来的窗口过程(Windows提供),那么,MFC如何完成Win32下对话框窗口的功能呢?
考查模式对话框的创建过程。
CDialog:
DoModal用来创建模式对话框窗口并执行有关任务,和DoModal相关的是MFC内部使用的成员函数CDialog:
PreModal和CDialog:
PostModal。
下面分别讨论它们的实现。
HWNDCDialog:
PreModal()
//cannotcallDoModalonadialogalreadyconstructedasmodeless
ASSERT(m_hWnd==NULL);
//allowOLEserverstodisablethemselves
AfxGetApp()->
EnableModeless(FALSE);
//得到父窗口
CWnd*pWnd=CWnd:
GetSafeOwner(m_pParentWnd,&
m_hWndTop);
//如同CWnd处理其他窗口的创建,设置一个窗口创建HOOK
AfxHookWindowCreate(this);
//返回父窗口的句柄
returnpWnd->
GetSafeHwnd();
voidCDialog:
PostModal()
//取消窗口创建前链接的HOOK
AfxUnhookWindowCreate();
//justincase
//MFC对话框对象和对应的Windows对话框窗口分离
Detach();
//m_hWndTop是当前对话框的父窗口或所属窗口,则恢复它
if(:
IsWindow(m_hWndTop))
EnableWindow(m_hWndTop,TRUE);
m_hWndTop=NULL;
EnableModeless(TRUE);
intCDialog:
DoModal()
//canbeconstructedwitharesourcetemplateorInitModalIndirect
ASSERT(m_lpszTemplateName!
=NULL||
m_hDialogTemplate!
=NULL||m_lpDialogTemplate!
=NULL);
//加载对话框资源
LPCDLGTEMPLATElpDialogTemplate=m_lpDialogTemplate;
HGLOBALhDialogTemplate=m_hDialogTemplate;
HINSTANCEhInst=AfxGetResourceHandle();
//查找资源(见9.5.2节),找到了就加载它
if(m_lpszTemplateName!
hInst=AfxFindResourceHandle(m_lpszTemplateName,RT_DIALOG);
HRSRChResource=
FindResource(hInst,m_lpszTemplateName,RT_DIALOG);
hDialogTemplate=LoadResource(hInst,hResource);
//锁定加载的资源
if(hDialogTemplate!
lpDialogTemplate=(LPCDLGTEMPLATE)LockResource(hDialogTemplate);
//return-1incaseoffailuretoloadthedialogtemplateresource
if(lpDialogTemplate==NULL)
return-1;
//创建对话框前禁止父窗口,为此要调用PreModal得到父窗口句柄
HWNDhWndParent=PreModal();
CWnd*pParentWnd=CWnd:
FromHandle(hWndParent);
BOOLbEnableParent=FALSE;
if(hWndParent!
=NULL&
&
:
IsWindowEnabled(hWndParent))
EnableWindow(hWndParent,FALSE);
bEnableParent=TRUE;
//创建对话框,注意是无模式对话框
TRY
//链接一个HOOK到HOOK链以处理窗口创建,
//如同4.4.1节描述的CWnd类窗口创建一样
//CreateDlgIndirect间接调用:
CreateDlgIndirect,
//最终调用了:
CreateWindowEX来创建对话框窗口。
//HOOK过程_AfxCbtFilterHook用子类化的方法
//取代原来的窗口过程为AfxWndProc。
if(CreateDlgIndirect(lpDialogTemplate,CWnd:
FromHandle(hWndParent),hInst))
if(m_nFlags&
WF_CONTINUEMODAL)
//entermodalloop
DWORDdwFlags=MLF_SHOWONIDLE;
//RunModalLoop接管整个应用程序的消息处理
if(GetStyle()&
DS_NOIDLEMSG)
dwFlags|=MLF_NOIDLEMSG;
VERIFY(RunModalLoop(dwFlags)==m_nModalResult);
//hidethewindowbeforeenablingtheparent,etc.
if(m_hWnd!
SetWindowPos(NULL,0,0,0,0,SWP_HIDEWINDOW|
SWP_NOSIZE|SWP_NOMOVE|
SWP_NOACTIVATE|SWP_NOZORDER);
CATCH_ALL(e)
DELETE_EXCEPTION(e);
m_nModalResult=-1;
END_CATCH_ALL
//Enable并且激活父窗口
if(bEnableParent)
EnableWindow(hWndParent,TRUE);
GetActiveWindow()==m_hWnd)
SetActiveWindow(hWndParent);
//:
EndDialog仅仅关闭了窗口,现在销毁窗口
DestroyWindow();
PostModal();
//必要的话,解锁/释放资源
=NULL||m_hDialogTemplate!
UnlockResource(hDialogTemplate);
FreeResource(hDialogTemplate);
returnm_nModalResult;
从DoModal的实现可以看出:
它首先Disable对话框窗口的父窗口;
然后使用:
CreateIndrectDialog创建对话框窗口,使用子类化的方法用AfxWndProc(或者AfxBaseProc)替换了原来的窗口过程,并把原来的窗口过程保存在CWnd的成员变量m_pfnSuper中。
原来的窗口过程就是:
DialogBox等创建对话框窗口时指定的,是Windows内部提供的对话框“窗口类”的窗口过程。
取代(Subclass)原来“窗口类”的窗口过程的方法如同4.4.1节描述的CWnd:
Create。
在:
CreateIndirectDialog创建对话框窗口后,会发送WM_INITDIALOG消息给对话框的对话框过程(必要的话,还有WM_SETFONT消息)。
但是MFC取代了原来的对话框窗口过程,这两个消息如何送给对话框过程呢?
处理方法如下节所描述。
使用原对话框窗口过程作消息的缺省处理
对话框的消息处理过程和其他窗口并没有什么不同。
这里主要分析的是如何把一些消息传递给对话框原窗口过程处理。
下面,通过解释MFC对WM_INITDIALOG消息的处理来解释MFC窗口过程和原对话框窗口过程的关系及其协调作用。
MFC提供了WM_INITDIALOG消息的处理函数CDialog:
HandleInitDialog,WM_INITDIALOG消息按照标准Windows的处理送给HandleInitDialog处理。
HandleInitDialog调用缺省处理过程Default,导致CWnd的Default函数被调用。
Default的实现如下:
LRESULTCWnd:
Default()
//callDefWindowProcwiththelastmessage
_AFX_THREAD_STATE*pThreadState=_afxThreadState.GetData();
returnDefWindowProc(pThreadState->
m_lastSentMsg.message,
pThreadState->
m_lastSentMsg.wParam,
m_lastSentMsg.lParam);
顺便指出,从Default的实现可以看出线程状态的一个用途:
它把本线程最新收到和处理的消息记录在成员变量m_lastSentMsg中。
在Default的实现中,CWnd的DefWindowsProc被调用,其实现如下:
DefWindowProc(UINTnMsg,
WPARAMwParam,LPARAMlParam)
//若“窗口超类(SuperClass)”的窗口过程m_pfnSuper非空,则调用它
if(m_pfnSuper!
return:
CallWindowProc(m_pfnSuper,m_hWnd,nMsg,wParam,lParam);
//在MFC中,GetSuperWndProcAddr的作用就是返回m_pfnSuper,为什么还
//要再次调用呢?
因为虽然该函数现在是Obsolete,但原来曾经是有用的。
如
//果返回非空,就调用该窗口过程进行处理,否则,由Windows进行缺省处理。
WNDPROCpfnWndProc;
if((pfnWndProc=*GetSuperWndProcAddr())==NULL)
DefWindowProc(m_hWnd,nMsg,wParam,lParam);
CallWindowProc(pfnWndProc,m_hWnd,nMsg,wParam,lParam);
综合上述分析,HandleInitDialog最终调用了窗口过程m_pfnSuper,即Windows提供给“对话框窗口类”的窗口过程,于是该窗口过程调用了对话框过程AfxDlgProc,导致虚拟函数OnInitDialog被调用。
顺便提一下,CWnd:
AfxCallWndProc在处理WM_INITDIAL