⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mfc13.php

📁 php网页版的mfc教程 不是十分详细 但是很精练 我是新手不是十分会欣赏
💻 PHP
📖 第 1 页 / 共 5 页
字号:
  <P align=justify>ASSERT(button.fsStyle == TBSTYLE_BUTTON);</P>
  <P align=justify>if (!DefWindowProc(TB_ADDBUTTONS, 1, 
(LPARAM)&amp;button))</P>
  <P align=justify>return FALSE;</P>
  <P align=justify>}</P>
  <P align=justify>}</P>
  <P align=justify>//记录按钮个数到成员变量m_nCount中</P>
  <P align=justify>m_nCount = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);</P>
  <P align=justify></P>
  <P align=justify>//稍后放置按钮</P>
  <P align=justify>m_bDelayedButtonLayout = TRUE;</P>
  <P align=justify></P>
  <P align=justify>return TRUE;</P>
  <P align=justify>}</P>
  <P 
  align=justify>函数的参数1是一个数组,数组的各个元素就是命令ID;参数2是按钮的个数。首先,SetButtons删除工具条原来的按钮;然后,添加新的按钮,若命令ID数组非空,则把每一个按钮和命令ID对应并分配位图索引,否则设置空按钮并返回FALSE;最后,记录按钮个数。</P>
  <P 
  align=justify>从SetButtons的实现可以看出,对工具条的所有操作都是通过工具条“窗口类”的窗口过程完成的,SetSizes、LoadBitmap也是如此,这里不作讨论。</P>
  <P align=justify></P>
  <LI>状态栏和对话框工具栏的创建 
  <P></P></LI></OL>
<P align=justify>至此,分析了MFC创建工具条窗口的过程。对于状态栏和对话框工具栏有类似的步骤,但也有不同之处。</P>
<P 
align=justify>CStatusBar的Create使用“msctls_statusbar32”“窗口类”创建状态栏,窗口ID为AFX_IDW_STATUS_BAR(0XE801),然后通过成员函数SetIndictors给状态栏分格,类似于给工具条添加按钮的过程,它实际上是通过状态栏“窗口类”的窗口过程完成的。</P>
<P 
align=justify>CDialogBar的Create使用CreateDlg创建对话框工具栏,类似于CFormView的过程。在工具栏窗口创建之后,要添加到父窗口的工具栏列表中,这通过CControlBar::OnCreate完成。这样创建的结果导致窗口过程使用MFC的统一的窗口过程,相应“窗口类”的窗口过程也将在缺省处理中被调用,这一点如同CFormView和CDialog中所描述的。在初始化对话框的时候完成了各个控制按钮的添加。</P>
<P align=justify>CStatusBar和CdialogBar都没有处理消息WM_NCCREATE。</P>
<P align=justify>关于CStautsBar和CDialogBar创建过程的具体实现,这里不作详细讨论了。</P>
<OL>
  <OL>
    <OL>
      <P align=justify>
      <LI><A name=_Toc452641010></A><A name=_Toc457299141></A><B>控制条的销毁</B> 
      <P></P>
      <P align=justify>描述了控制条的创建,顺便考察其销毁的设计。</P>
      <P 
      align=justify>工具条、状态栏等这些控制窗口都要使用DestroyWindow来销毁,所有有关操作集中由CControlBar处理。CControlBar覆盖了虚拟函数DestroyWindow、PostNcDestroy和消息处理函数OnDestroy。</P>
      <P 
      align=justify>当然,各个派生类的虚拟析构函数被实现。如果成员变量m_bAutoDelete为TRUE,则动态创建的MFC窗口将自动销毁。</P>
      <P align=justify></P>
      <LI><A name=_Toc452641011></A><A name=_Toc457299142></A><B>处理控制条的位置</B> 
      <P></P>
      <OL>
        <P align=justify>
        <LI><B><A name=_Toc457299143></A>计算控制条位置的过程和算法</B> 
        <P></P>
        <P 
        align=justify>工具条等控制条是作为一个子窗口在父边框窗口内显示的。为了处理控制条的布置(Layout),首先需要计算出控制条的尺寸大小,这个工作被委派给工具条等控制窗口自己来完成。为此,CControlBar提供了两个函数来达到这个目的:CalcFixLayout,CalcDynamicLayout。这两个函数都是虚拟函数。各个派生类都覆盖了这两个或者其中一个函数,用来计算自身的尺寸大小。这些计算比较琐碎,在此不作详细讨论。其次,在父窗口位置或者大小变化时,控制条的大小和位置要作相应的调整。</P>
        <P align=justify>下面,描述MFC确定或者更新工具条、状态栏等位置的步骤:</P>
        <P 
        align=justify>(1)边框窗口在必要的时候调用虚拟函数RecalcLayout来重新放置它的控制条和客户窗口,例如在创建窗口时、响应消息WM_SIZE时(见5.3.3.5节)边框窗口的初始化)。</P>
        <P 
        align=justify>(2)CFrameWnd::RecalcLayout调用CWnd的成员函数RepositionBars完成控制条窗口的重新放置。</P>
        <P align=justify>(3)CWnd::RepositionBars作如下的处理:</P>
        <P 
        align=justify>RepositionBars首先给各个控制子窗口发送(Send)MFC内部使用的消息WM_SIZEPARENT,把窗口客户区矩形指针传递给它们,给它们一个机会来确认自己的尺寸。</P>
        <P 
        align=justify>然后,各个控制子窗口用OnSizeParent响应WM_SIZEPARENT消息;ControlBar实现了消息处理函数OnSizeParent,它调用CalcDynamicLayout等函数确定本窗口的大小,并从客户区矩形中减去自己的尺寸。</P>
        <P 
        align=justify>在所有的控制子窗口处理了OnSizeParent消息之后,RepositonBars利用返回的信息调用函数CalcWindowRect计算客户区窗口(MDI客户窗口、View等)的大小。</P>
        <P 
        align=justify>最后,调用::EndDeferWindowPos或者::SetWindowPos放置所有的窗口(控制子窗口和客户窗口)。</P>
        <P 
        align=justify>在窗口被放置的时候,发送消息WM_WINDOWPOSCHANGING和WM_WINDOWPOSCHANGED。MFC的实现中,控制窗口响应了前一个消息,消息处理函数是OnWindowPosChanging。CControlBar、CToolBar和CStatusBar等实现了消息处理函数OnWindowPosChanging。</P>
        <P align=justify></P>
        <P 
        align=justify>上述处理过程所涉及的这些函数中,RecalcLayout是CFrameWnd定义的虚拟函数;RepostionBars是CWnd的成员函数;CalcaWindowRect是CWnd的虚拟函数;OnSizeParent是CControlBar定义的消息处理函数;OnWindowPosChanging是CToolbar、CStatusBar、CDockBar等CControlBar派生类定义的消息处理函数。</P>
        <P align=justify>下面,对其中两个函数RecalcLayout和RepositionBars作一些分析。</P>
        <P align=justify></P>
        <LI><A name=_Toc457299144></A><B>CFrameWnd的虚拟函数RecalcLayout</B> 
        <P></P>
        <P align=justify>RecalcLayout的实现如下:</P>
        <P align=justify>void CFrameWnd::RecalcLayout(BOOL bNotify)</P>
        <P align=justify>{</P>
        <P align=justify>//RecalcLayout是否正在被调用</P>
        <P align=justify>if (m_bInRecalcLayout)</P>
        <P align=justify>return;</P>
        <P align=justify></P>
        <P align=justify>m_bInRecalcLayout = TRUE;</P>
        <P align=justify>// clear idle flags for recalc layout if called 
        elsewhere</P>
        <P align=justify>if (m_nIdleFlags &amp; idleNotify)</P>
        <P align=justify>bNotify = TRUE;</P>
        <P align=justify>m_nIdleFlags &amp;= ~(idleLayout|idleNotify);</P>
        <P align=justify></P>
        <P align=justify>//与OLE相关的处理</P>
        <P align=justify>#ifndef _AFX_NO_OLE_SUPPORT</P>
        <P align=justify>// call the layout hook -- OLE support uses this 
        hook</P>
        <P align=justify>if (bNotify &amp;&amp; m_pNotifyHook != NULL)</P>
        <P align=justify>m_pNotifyHook-&gt;OnRecalcLayout();</P>
        <P align=justify>#endif</P>
        <P align=justify></P>
        <P align=justify>//是否包含浮动(floating)控制条的边框窗口(CMiniFrameWnd类)</P>
        <P align=justify>if (GetStyle() &amp; FWS_SNAPTOBARS)</P>
        <P align=justify>{</P>
        <P align=justify>//计算控制条和边框窗口的位置、尺寸并设置它们的位置</P>
        <P align=justify>CRect rect(0, 0, 32767, 32767);</P>
        <P align=justify>RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, 
        reposQuery,</P>
        <P align=justify>&amp;rect, &amp;rect, FALSE);</P>
        <P align=justify>RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, 
        reposExtra,</P>
        <P align=justify>&amp;m_rectBorder, &amp;rect, TRUE);</P>
        <P align=justify>CalcWindowRect(&amp;rect);</P>
        <P align=justify>SetWindowPos(NULL, 0, 0, rect.Width(), 
        rect.Height(),</P>
        <P align=justify>SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);</P>
        <P align=justify>}</P>
        <P align=justify>else</P>
        <P align=justify>//是普通边框窗口,则设置其所有子窗口的位置、尺寸</P>
        <P align=justify>RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST,</P>
        <P align=justify>reposExtra, &amp;m_rectBorder);</P>
        <P align=justify></P>
        <P align=justify>//本函数处理完毕</P>
        <P align=justify>m_bInRecalcLayout = FALSE;</P>
        <P align=justify>}</P>
        <P 
        align=justify>该函数主要的目的是调用RepositionBars函数,它分两种情况来调用RepositionBars函数。一种情况是当前边框窗口为浮动控制条的包容窗口(微型边框窗口)时;另一种情况是当前边框窗口为普通边框窗口时。</P>
        <P align=justify></P>
        <LI><A name=_Toc457299145></A><B>CWnd的成员函数RepositionBars</B> 
        <P></P></LI></OL>
      <P align=justify>RepositionBars的实现如下:</P>
      <P align=justify>void CWnd::RepositionBars(UINT nIDFirst, UINT nIDLast, 
      UINT nIDLeftOver,</P>
      <P align=justify>UINT nFlags, LPRECT lpRectParam, LPCRECT lpRectClient, 
      BOOL bStretch)</P>
      <P align=justify>{</P>
      <P align=justify>ASSERT(nFlags == 0 || nFlags == reposQuery || nFlags == 
      reposExtra);</P>
      <P align=justify></P>
      <P align=justify>AFX_SIZEPARENTPARAMS layout;</P>
      <P align=justify>HWND hWndLeftOver = NULL;</P>
      <P align=justify></P>
      <P align=justify>layout.bStretch = bStretch;</P>
      <P align=justify>layout.sizeTotal.cx = layout.sizeTotal.cy = 0;</P>
      <P align=justify>if (lpRectClient != NULL)</P>
      <P align=justify>layout.rect = *lpRectClient; //从参数6得到客户区</P>
      <P align=justify>else</P>
      <P align=justify>//参数lpRectClient空,得到客户区域</P>
      <P align=justify>GetClientRect(&amp;layout.rect);</P>
      <P align=justify></P>
      <P align=justify>if (nFlags != reposQuery)</P>
      <P align=justify>//准备放置各个子窗口(layout)</P>
      <P align=justify>layout.hDWP = ::BeginDeferWindowPos(8); // reasonable 
      guess</P>
      <P align=justify>else</P>
      <P align=justify>layout.hDWP = NULL; // not actually doing layout</P>
      <P align=justify></P>
      <P align=justify>//按一定顺序给各个控制条发送父窗口resize的消息;</P>
      <P align=justify>//各个控制条窗口收到消息后,从客户区中扣除自己使用的区域;</P>
      <P align=justify>//并且必要的话每个控制窗口调用::DeferWindowPos</P>
      <P align=justify>//剩下的区域留给nIDLeftOver子窗口</P>
      <P align=justify>for (HWND hWndChild = ::GetTopWindow(m_hWnd); hWndChild 
      != NULL;</P>
      <P align=justify>hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))</P>
      <P align=justify>{</P>
      <P align=justify>UINT nIDC = _AfxGetDlgCtrlID(hWndChild);</P>
      <P align=justify>CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);</P>
      <P align=justify>//如果是指定的nIDLeftOver子窗口,则保存其窗口句柄;</P>
      <P align=justify>//否则,是控制条窗口,给它们发送WM_SIZEPARENT消息</P>
      <P align=justify>if (nIDC == nIDLeftOver)</P>
      <P align=justify>hWndLeftOver = hWndChild;</P>
      <P align=justify>else if (nIDC &gt;= nIDFirst &amp;&amp; nIDC &lt;= 
      nIDLast &amp;&amp; pWnd != NULL)</P>
      <P align=justify>//如果layout-&gt;hDWP非空, OnSizeParent则将执行窗口布置的操作</P>
      <P align=justify>::SendMessage(hWndChild, WM_SIZEPARENT, 0, 
      (LPARAM)&amp;layout);</P>
      <P align=justify>}</P>
      <P align=justify></P>
      <P align=justify>//如果是reposQuery,则得到客户区矩形,返回</P>
      <P align=justify>if (nFlags == reposQuery)</P>
      <P align=justify>{</P>
      <P align=justify>ASSERT(lpRectParam != NULL);</P>
      <P align=justify>if (bStretch)</P>
      <P align=justify>::CopyRect(lpRectParam, &amp;layout.rect);</P>
      <P align=justify>else</P>
      <P align=justify>{</P>
      <P align=justify>lpRectParam-&gt;left = lpRectParam-&gt;top = 0;</P>
      <P align=justify>lpRectParam-&gt;right = layout.sizeTotal.cx;</P>
      <P align=justify>lpRectParam-&gt;bottom = layout.sizeTotal.cy;</P>
      <P align=justify>}</P>
      <P align=justify>return;</P>
      <P align=justify>}</P>
      <P align=justify></P>
      <P align=justify>//其他情况下(reposDefault、reposExtra),则需要执行Layout操作</P>
      <P align=justify></P>
      <P align=justify>//处理hWndLeftOver(nIDLeftOver子窗口)</P>
      <P align=justify>if (nIDLeftOver != 0 &amp;&amp; hWndLeftOver != NULL)</P>
      <P align=justify>{</P>
      <P align=justify>CWnd* pLeftOver = CWnd::FromHandle(hWndLeftOver);</P>
      <P align=justify>// allow extra space as specified by lpRectBorder</P>
      <P align=justify>if (nFlags == reposExtra)</P>
      <P align=justify>{</P>
      <P align=justify>ASSERT(lpRectParam != NULL);</P>
      <P align=justify>layout.rect.left += lpRectParam-&gt;left;</P>
      <P align=justify>layout.rect.top += lpRectParam-&gt;top;</P>
      <P align=justify>layout.rect.right -= lpRectParam-&gt;right;</P>
      <P align=justify>layout.rect.bottom -= lpRectParam-&gt;bottom;</P>
      <P align=justify>}</P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -