基于对话框的mfc,mfc对话框控件
http://hi . Baidu . com/xiaori da 21/blog/item/8d 8 EB 77 a 22 eedee 52 e 73 b 39 e . html
CWnd类
我们在屏幕上看到的所有对象都与windows有关。它们要么派生自CWnd,属于继承关系,比如对话框、工具栏、状态栏、子控件等。或者CWnd合成的,属于服务员和客户的关系,比如图标,菜单,显示设备。
CWnd类封装的窗口操作主要包括窗口创建和销毁、窗口样式、窗口状态、窗口子类化、获取指定窗口等。
当然,CWnd还实现了其他功能:
1.画窗户。
GetDC()//获取客户区显示设备上下文。
GetWindowsDC()//获取整个窗口的显示设备上下文。
ReleaseDC()
BeginPaint()
EndPaint()
PrintClient()
redraw window()///重绘工作区的一个区域。
2.操作窗口子控件。
GetDlgItem():获取(临时)控件对象指针。
SetDlgItemText()和GetDlgItemText():设置并获取控件标题。
SubclassDlgItem():将控制句柄与相应的类相关联。
DlgDirList()和DlgDirListComboBox():用文件列表或目录列表填充(组合框)列表框。
CheckDlgButton()和CheckRadioButton():设置复选框(单选按钮)的状态。
GetNextDlgTabItem():获取下一个WS_TABSTOP样式控件。
3.窗口计时器
SetTimer():设置计时器。
KillTimer():销毁计时器
4.窗口消息的相关函数
GetCurrentMessage():获取当前处理的消息。
PreTranslateMessage():一个重载的虚函数。由UI线程的消息循环调用,可以对窗口接收到的消息进行过滤,并将过滤后的消息进行分发
SendMessage():向该窗口发送一条消息。调用窗口函数直接处理消息,而不是消息循环。直到窗口结束,该函数才会返回。
PostMessage():向该窗口发送一条消息。将消息放入消息队列并立即返回。
Default():为所有窗口消息提供默认处理。您可以对不需要处理的消息或希望默认处理的消息使用Default()。
5.默认消息处理功能
在实际编程中,很少调用Default(),因为对于大多数消息,CWnd类都定义了相应的处理函数,封装了Default()的调用。同时还有一些特殊的消息,比如WM_SYSCOLORCHANGE。仅执行系统级处理是不够的。框架必须完成一些消息的例行操作。
////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/FB 89 bb 29 AC 9 a 74 f 698250 a6a . html
,CFrameWnd类
用文档/视图结构编写应用程序时,CFrameWnd是管理视图和文档对象的主窗口。视图和控制栏成为CFrameWnd的子窗口,它们共享客户区,它们的位置被CFrameWnd有效地安排。
CFrameWnd的建立
Creage()和LoadFrame()。前者主要创建窗口,后者在调用前者之前组织参数。
LoadFrame()的形参简洁,很多主窗体都是在创建窗口的时候初始化的。
2.管理视图对象。
视图无非是主框架窗口的一个子窗口,ID为AFX_IDW_PANE_FIRST,有边框,由CFrameWnd封装创建。成员CFrameWnd:OnCreateClient()用于创建视图窗口,该窗口在该类的WM_CREATE消息处理函数中调用。一个主窗口可以包含多个视图,这些视图或者是通过在客户区拆分CSplitterWnd创建的,或者是直接作为子窗口在客户区创建的。
创建主窗口后,也创建了视图。通常,初始化时会调用CFrameWnd:InitialUpdateFrame()。此函数将第一个视图ID设置为AFX _ IDW _窗格_优先。
3.管理控制条款
主窗口有丰富的控制条,都是从CControlBar派生出来的。
CFrameWnd封装了对这些的操作,比如:
EnableDockinng();
DockControlBar();
float control bar();
ShowControlBar();
save barstate();
LoadBarState();
GetDockState();
SetDockState();
SetMessageText();
重新布局()
4.发送命令消息。
命令是指菜单、工具栏、快捷键和命令按钮向其窗口发送的WM_COMMAND消息。主框架窗口通常包含应用系统的主菜单和工具栏,而快捷键通常安装在主窗口的LoadFrame()中,它们向主窗口发送命令消息。
除了WM_COMMAND,其他以WM_开头的消息称为窗口消息。窗口消息与某个窗口密切相关,应该由接收消息的窗口来处理。命令消息通常与特定窗口无关。
CCmdTarget类定义了一个OnCmdMsg()虚函数,用于处理命令消息,该函数可以由派生类重载。CFrameWnd通过重载这个函数来实现命令消息的分发:首先将命令消息发送给活动视图;如果视图没有处理它,它将被发送到相关的文档对象;如果视图和文档都没有处理过消息,即没有建立消息的消息映射,则由主窗口自己处理;如果主窗口没有处理它,它将最终尝试应用该类;如果仍然没有,消息将由默认流程处理。
注意:主窗口直接调用view和application类的OnCmdMsg()虚函数处理命令消息,不通过SendMessage()或PostMessage()转发消息。OnCmdMsg()只在类中搜索消息映射表,寻找这个命令的处理函数。如果没有找到,返回。因此,视图类只能通过消息映射处理主窗口转发的命令消息。如果使用CView:WindowProc()来捕获这类消息,将一无所获。
5.必要的消息处理
为了管理控制条和视图,CFrameWnd为几个窗口消息建立了消息映射,经过特殊处理。
OnInitMenuPopup();
OnEnterIdle();
OnMenuSelect();
OnToolTipText();
onupdatekey indicator();
OnUpdateControlBarMenu();
OnSize();
onh scroll();
onv scroll();
OnClose();
////////////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/9 CBD 5507 Fe 6 c 73 c 57 a 894751 . html
CView类
1.关联文档对象
一个视图对象只与一个文档对象相关联,但是一个文档对象可以与多个视图相关联,并且每个视图对象以不同的形式表示文档数据。
在文档/视图框架程序中,文档对象总是建立在视图之前,但是在视图的WM_CREATE消息处理函数中,它与文档对象的关联被建立,当前视图被添加到文档对象的视图列表中,因为一个文档可以关联多个视图。同时,view类定义了成员函数GetDocument(),该函数返回文档对象的指针。视图总是在文档对象之前被销毁。在视图析构函数中,它与文档对象联系人m_pDocument- RemoveView(this)相关联。
2.绘制视图。
窗口绘制总是在WM_PAINT消息处理中完成。当需要绘制窗口时,它会从系统接收WM_PAINT消息。在绘制过程中,我们需要准备显示设备句柄,最后释放句柄。但是我们不需要加载WM_PAINT消息处理函数OnPaint(),只需要在OnDraw()中画图,OnDraw()准备一个显示设备,最后不需要发布,这些都是OnPaint()为我们准备的。
OnDraw()在视图基类CView中定义为纯虚函数:virtual void OnDraw(CDC * pDC)=0;
因此,CView是一个抽象基类,不能实例化,而派生类必须重载OnDraw()。
3.更新时的虚函数virtual void(cview * PS ender,lparam,cobject *)
当文档数据发生变化时,文档对象调用CDocument:UpdateAllView()通知所有视图,视图的OnUpdate()成员被调用。因此,重载OnUpdate()应该能够根据需要在视图上反映文档数据的变化。而CView:OnUpdate()只是让客户区失效,导致客户区被重绘。
4.虚函数virtual void OnInitialUpdate()
它由框架在初始创建后调用OnCreate(),或者在FileNew、FileOpen命令后调用。基类CView:OnInitalUpdate()简单地调用OnUpdate(),可以重载它来完成初始化,但注意它可能会被多次调用。
5.虚函数virtual void calcwindowrect(lprect lpclientrect,unit nadjusttype)
每当主框架窗口的客户区大小发生变化,或者控制条的位置发生变化,需要重新排列客户区时,就调用这个函数,根据视图客户区的大小计算视图窗口的大小。
我们知道,安排主窗口客户区是由CFrameWnd:RecalcLayout()完成的。显然,视图的CalcWindowRect()函数也是由其触发和调用的。主窗口的客户区大小被所有的控制条缩小,剩余的区域被分配给视图。该区域作为参数传递给CalcWindowRect()。在CalcWindowRect()函数中,您需要计算视图窗口的大小。
6.虚函数virtual void PostNcDestroy()
视图窗口关闭时调用的成员函数,执行与cframe wnd:postncdestate相同的功能,即删除视图对象。
void CView:PostNcDestroy()
{删除此内容;}
这样,即使视图是在堆中构造的,也不用担心视图的释放。
7.虚函数virtual bool oncmdmmsg(uint,int,void *,afx _ cmdhandlerinfo *)
cview:oncmdmmsg首先查找自己的命令消息映射,如果自己不处理消息,就把机会留给自己关联的document对象。
8.激活视图上的虚函数virtual void(bool,cview *,cview *)
当视图被激活或者从活动状态变为非活动状态时,调用这个函数来通知视图。CView:OnActivateView只是将此视图设置为焦点的实现。
//////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/24 b 83838 f 7 C3 d 9 CAD 4622556 . html
CDialog类
通过对话框模板创建对话框时,只需要一个以模板为实参的创建命令,如CDialog:Create,就可以完成对话框窗口及其子控件的创建,所有的创建细节都由对话框模板指示。
模式对话框的消息循环
当调用对话框的Domodal()成员时,将创建模式对话框。它可以禁止它所属的主窗口,以及它的子窗口(重叠窗口和普通弹出窗口除外)。
1.创建模式对话框和模式循环
其实“模态”并不是对话框的专利,模态特征都封装在CWnd中。如果采用与模态对话框相同的创建方法,普通窗口也可以是模态的。这个方法是在表单创建后调用CWnd:RunModalLoop()模式循环函数。类似CWnd:Run(),也是消息循环泵,CWnd:RunModalLoop()的消息处理更复杂。
CDialog:DoModal()函数的操作过程:首先AfxGetResourceHandle()和LoadResource(hInst,hResource)加载对话框资源。模板对话框建立之前,EnableWindow(hWndParent,FALSE)禁止父窗口的鼠标键盘输入,禁止父窗口,间接禁止父窗口的下属窗口,但不包括下属的重叠窗口和普通弹出窗口。CreateDLGINDirect (LP对话框模板,CWND: From Handl (HWND Parent),Hinst)通过资源模板创建对话框及其子控件。创建成功后,它进入模式循环RunModalLoop()。当用户选择IDOK和IDCANCEL时,模式循环退出,对话框将被销毁。* enable window(hWndParent,TRUE)恢复父窗口的工作状态,间接恢复其兄弟窗口。SetActiveWindows(hWndParent)激活父窗口,DestroyWindow()销毁对话框。
modalloop()实现的消息循环:该消息循环完成了UI线程消息循环(CWinThread:Run封装)的所有功能,同时增加了必要的处理代码,用于处理模态窗口的特殊消息。模态窗口建立后,进入这个循环,消息循环泵临时代替UI线程的消息循环泵,为所有窗口提取和分发信息。但是,除非使用PostMessage()命令,否则所有被禁止的窗口都无法接收来自鼠标和键盘的消息。
RunModalLoop()的实现过程:RunModalLoop(DWORD dwFlags)参数可以做地下三个的组合:MLF_NOIDLEMSG(当消息队列空闲时,WM_ENTERIDLE消息不会发送到当前主窗口)
MLF_NOKICKIDLE(当消息队列空闲时,WM_KICKIDLE消息不发送到当前模式对话框)
MLF_SHOWONIDLE(当消息队列空闲时,刷新并显示当前对话框(仅一次))
int CWnd:RunModalLoop(DWORD dw flags)
{
ASSERT(:is window(m _ hWnd));//窗口必须已经创建并且不处于模式状态
//m_nFlags是WF_MODALLOOP来标记进入模式。
断言(!(m _ nFlags WF _ MODALLOOP));
//以下变量用于空闲处理
BOOL bIdle=TRUE
LONG lidle count=0;
BOOL b showidle=(dw flags MLF _ showon idle)
!(get style()WS _ VISIBLE);
HWND HWND parent=:get parent(m _ HWND);
m _ nFlags =(WF _ modal loop WF _ continue model);
MSG * pMsg=AfxGetThread()-m _ MSG cur;//获取存储当前消息的缓冲区
//获取并调度消息,直到模式状态结束。
for(;)
{
ASSERT(continue model());
//第一阶段,判断是否可以执行空闲进程。
while(比德尔!* PeekMessage(pMsg,NULL,NULL,NULL,PM_NOREMOVE))
{
ASSERT(continue model());
//如果需要,在空闲时显示对话窗口
如果(b显示)
{
show window(SW _ show normal);
update window();
bShowIdle=FALSE
}
//执行空闲处理。
//必要时向父窗口发送WM_ENTERIDLE消息
如果(!(dw flags MLF _ NOIDLEMSG)hwnd parent!=NULL lIdleCount==0)
{
*发送消息(hWndParent,WM_ENTERIDLE,
MSGF _对话框,(LPARAM)m _ hWnd);
}
//必要时向父窗口发送WM_KICKIDLE消息
if ((dwFlags MLF_NOKICKIDLE)
!SendMessage(WM_KICKIDLE,MSGF_DIALOGBOX,lIdleCount))
{
//终止空闲处理
bIdle=FALSE
}
}
//第二阶段,提取和分发消息
做
{
ASSERT(continue model());
//如果是WM_QUIT消息,将消息发送到消息队列并返回;否则,发送消息。
如果(!AfxGetThread()- PumpMessage())
{
AfxPostQuitMessage(0);
return-1;
}
//您收到了一条特殊消息。是否要刷新显示此对话框的窗口?
如果(b显示
(pMsg-message==0x 118 pMsg-message==WM _ SYSKEYDOWN))
{
show window(SW _ show normal);
update window();
bShowIdle=FALSE
}
如果(!continue model())////可能是关闭当前对话消息,确定是否结束模式循环。
转到ExitModal
//发送“正常”消息后,重启空闲处理。
if(AfxGetThread()-IsIdleMessage(pMsg))
{
bIdle=TRUE
lidle count=0;
}
} while (:PeekMessage(pMsg,NULL,NULL,NULL,PM _ no remove));
}
exit mode://用户关闭了对话框,结束了模式循环。
m _ nFlags=~(WF _ modal loop WF _ continue model);
返回m _ nModalResult
}
与Run()不同,RunModalLoop()可以向父窗口发送WM_ENTERIDLE消息或者向当前窗口发送与IDLE消息等价的WM_KICKIDLE消息,使得对话框在空闲时能够完成某些操作。允许同时刷新显示对话框。但是注意,这里没有调用CWinThread:OnIdle()。
在发送WM_KICKIDLE消息时,由于没有在消息泵中分发,所以只能用SendMessage()发送,而不能用PostMessage()。
2.结束模式循环。
只需在对话框中调用CDialog:EndDialog()即可结束模式循环。结束后,必须调用DestroyWindow()来销毁对话框(DoModal()在退出前完成)。要用CDialog:Create()创建无模式,必须自己调用EndDialog()和DestroyWindow()。
3.创建一个公共模式对话框。
(1)调用EnableWindow()禁用程序的主窗口。
(2)使用CWnd:Create()等创建命令创建此窗口。您可以制作弹出窗口或重叠窗口。
(3)调用模式循环函数RunModalLoop(DWORD dwFlags),根据实际需要设置参数,如果需要进行空闲处理,可以手动添加消息映射。
(4)关闭窗口时,根据实际需要调用EndModalLoop(int nResult)结束代码。
(5)激活主窗口,调用DestroyWindow()销毁当前模态窗口。确保在窗口被销毁之前模式循环已经结束。
//////////////////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/79988 df 3 Fe 53 EDC 30 b 46 e 05 c . html
对话框的命令消息路由
如果一个对话框的父窗口(无论弹出和重叠,无论模态还是非模态)是主框架或视图,那么该对话框的菜单命令可以在每个对象中进行处理,其处理路线为:对话框-视图-文档对象-主框架-应用程序类。一旦命令消息被处理,它将不会继续被传递。
首先,搜索对象的消息映射。如果对象没有处理过这个命令消息,如果命令ID在[0x8000,0xF000]的范围内,它将被传递下去,否则,处理将被终止。(命令ID in [0x8000,0xF000]:全局命令,包括菜单、快捷键、系统命令等。命令范围为[0xf000,0xffff]: Windows系统命令(未交付)。如果命令ID在[0x8000,0xF000]的范围内,它将被传递到负责命令路由的父窗口。如果父窗口没有被处理,它将被移交给应用程序类。当父窗口不是主框架窗口时,将其传递给application类是有意义的。
如果父窗口不是主框架,应用程序类得到最后一次处理它的机会;如果父窗口是主框架,则最后一个应用程序类(UI线程)的代码是多余的。如果父窗口是视图,而视图是主框架的子窗口,且对话框弹出或与窗口重叠,则不能被视图控制,最终会由主框架接管。
问题:为什么说“对话框的父窗口是视图,而视图是主框架的子窗口。当一个对话框弹出或与窗口重叠时,它不能被视图控制,但主框架最终会接管。”?有疑问…
////////////////////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/8 CD 26 af 82 ef 8 c 707d 8 f 9 FD 37 . html
1.搜索窗口
1、1根据标题和窗口类查找窗口。
CWnd类的静态函数FindWindow()或者同名的API函数,只要是重叠或者弹出的窗口都可以用来查找。
HWFindWindow (LPCTSTR LP类名,//目标窗口的窗口类名
LPCTSTR lpWindowName///目标窗口的窗口标题名);
1、2根据相对位置或隶属关系找到窗口。
API GetWindow()函数可用于枚举所有窗口。
Hwngetgetwindow (hwndhwnd,//作为引用对象的窗口句柄。
UINT nCmd//目标窗口和参考窗口之间的位置关系)
这样,当FindWindow()和GetWindow()结合使用时,前者可以找到Z-Order顺序最高的窗口,后者可以以此窗口为起点,反复枚举当前句柄的下一个窗口,从而得到所有符合条件的窗口。
/////////////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/694 f73d 3a 320 a0d 7 a9 EC 9 AC 8 . html
CWnd类封装了两个函数:GetClientRect()和GetWindowRect(),分别用于返回窗口的屏幕坐标的矩形区域和客户区的坐标。ScreenToClient()和ClientToScreen(),用于屏幕坐标和工作区坐标之间的转换。以上四个功能都是通过封装同名API实现的。
对于弹出窗口和重叠窗口,GetClientRect()和GetWindowRect()得到的rect大小不相等,因为客户区不包括标题栏、边框等区域;如果是子窗口,得到的rect大小相等,因为子窗口一般只有客户区。
//////////////////////////////////////////////////////////
http://hi . Baidu . com/xiaori da 21/blog/item/386 c 038 BD 80519 dbfd 1 f 10 de . html
1.windows窗口之间的关系包括所有和拥有关系、父子关系等。
操作系统为每个窗口实例分配一个内存空间,称为窗口实例的信息结构。这个结构包含一个窗口实例的所有信息,包括四个窗口句柄:1。此窗口实例中Z_Order最高的子窗口句柄;2.此窗口实例的下一个同级窗口的句柄(子窗口称为同级窗口);3.此窗口实例的父窗口句柄;4.此窗口实例的所有者窗口句柄。
二、桌面窗口(第一个窗口)
当windows初始化时,首先创建一个桌面窗口,所有其他窗口都显示在它上面。* GetDesktopWindow()可以获取桌面窗口的句柄。桌面窗口位于系统窗口层次结构的顶部。
三。顶级窗口(二级窗口)
它没有被设置为WS_CHILD样式的窗口,但是它是桌面的子窗口。虽然顶层窗口之间存在兄弟关系,但是它们可以建立一种所有权和拥有关系(所有者窗口和受控窗口)。受控窗口位于所有者窗口的前端,即它的Z_Order顺序可以通过激活所有者窗口来改进。当所有者窗口最小化时,受控窗口隐藏。当CreateWindow()和CreateWindowEx()用于创建顶级窗口时,参数hWndParent确定所有者窗口。如果hWndParent是子窗口,系统将搜索子窗口的父窗口,直到找到最近的顶层窗口作为所创建窗口的所有者。
四。子窗口(三楼及以下的窗口)
子窗口以同样的方式连接到父窗口。决定顶层窗口之间Z_Order顺序的规则也适用于子窗口,即由扩展样式WS_EX_TOPMOST和窗口激活顺序决定。
五、重叠窗口和弹出窗口的区别
都是顶级窗口。前者总是有一个标题栏和一个边框,WS_CLIPSIBLINGS样式总是自动设置的。调用CreateWindow()和CreateWindowEx()创建重叠窗口时,可以指定默认的窗口大小参数,即CW_USEDEFAULT,系统会设置初始窗口大小。弹出窗口也会自动设置WS_CLIPSIBLINGS样式,但其他样式必须专门指定,CW_USEDEFAULT不能作为初始大小。
链接地址:www..com/afarmer/archive/2011/05/06/2038974.html 3358号
本文来源:http://www..com/afarmer,一花园-欢迎转载请保留此来源信息。