基于对话框的mfc,mfc对话框控件

  基于对话框的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,一花园-欢迎转载请保留此来源信息。

基于对话框的mfc,mfc对话框控件