哪里有网站建设电话,房产中介网站模板,有搜索引擎作弊的网站,网站域名每年费用Windows控制窗口 Windows (Windows95或者以上版本) 提供了系列通用控制窗口#xff0c;其中包括 工具 条(ToolBar)、状态栏(StatusBar)、工具条提示窗口(ToolTip)。 Windows在一个DLL加载时 注册 个控制窗口的“窗口类”。例如#xff0c;工具条的“窗口类”是“ToolbarWindo…Windows控制窗口 Windows (Windows95或者以上版本) 提供了系列通用控制窗口其中包括 工具 条(ToolBar)、状态栏(StatusBar)、工具条提示窗口(ToolTip)。 Windows在一个DLL加载时 注册 个控制窗口的“窗口类”。例如工具条的“窗口类”是“ToolbarWindow32”状态栏的“窗口类”是“msctls_statusbar32”工具条提示窗口的“窗口类”是“tooltips_class32”。为了保证该DLL被加载使用控制“窗口类”前应该首先调用函数InitCommonControl。MFC在窗口注册函数AfxDeferRegisterClass中实现了这一点。见2.2.1节MFC下窗口的注册。 创建通用控制窗口可以使用专门的创建函数如创建工具条的函数::CreateToolBarEx创建状态栏的函数::CreateStatusBarEx。也可以调用窗口创建函数::CreateWindowEx但是需要指定预定义的“窗口类”必要的话还要其他步骤如使用“ToolbarWindow32”“窗口类”创建工具栏后还需要在工具栏中添加或者插入 按钮 。 一般通用控制可以指定控制窗口风格(Style)。例如具备风格CCS_TOP表示该控制窗口放到父窗口客户区的顶部具备CCS_BOTTOM表示该控制窗口在客户区的底部。具体的控制窗口类可以有特别的适合于自己的风格例如TTS_ALWAYSTIP表示只要光标落在工具栏的按钮上ToolTip窗口不论激活与否都会显示出来。 每一控制窗口类都有自己的窗口过程来处理自己的窗口消息实现特定的功能。控制窗口类的窗口过程由Windows提供。 工具条 工具条的窗口过程处理了必要的消息提供了 标准 工具条的功能例如工具条对客户化特征提供内在的支持用户可以通过一个客户化对话框来添加、修改、删除或者重新安排工具条按钮。这些特征是否可以被用户所用或者用到什么地步是可以由程序控制的。 工具条的窗口过程将自动设置工具条的 尺寸 大小和位置如果指定了控制窗口风格CCS_TOP或者CCS_BOTTOM则窗口过程把工具条放到父窗口客户区的顶部或者底部。窗口过程任何时候只要收到WM_SIZE或者TB_AUTOSIZE消息就自动地调整工具条的大小和位置。 工具条的按钮被选中后会产生一个命令消息它的窗口过程把该消息送给父窗口的窗口过程处理。 工具条中的按钮并不以子窗口的形式出现而是以字符或者位图按钮的方式显示每个按钮大小相同缺省是24*22个像素。每个按钮都有一个索引索引编号从0开始。每个按钮包括如下属性 按钮 的字符串索引位图索引风格状态命令ID 按钮可以有两种风格TBSTYLE_BUTTON和TBSTYLE_CHECK前者像一个 标准 按钮那样响应用户的按击后者响应每一次按击在按下和跳起两种状态之间切换。按钮响应用户的动作给父窗口发送一个包含了该按钮对应命令ID的命令消息。一般一个按钮的命令ID对应一个菜单项。 工具 条维护两个列表分别用来存放工具条按钮使用的字符串或者位图列表中的位图或者字符串从0开始编号编号和按钮的索引相对应。 工具条可以是Dockable泊位或者Floatable漂浮的。 工具条可以有TBSTYLE_TOOLTIPS风格如果具有这种风格则创建和 管理 一个Tooltip控制这是一个小的弹出式窗口用来显示描述按钮的文本平时该窗口隐藏当鼠标落到按钮上面并停留约一秒后才弹出在鼠标附近显示。 由于Tooltip窗口平时是隐藏的所以不能接收鼠标消息来决定何时显示本窗口。这样接收鼠标的窗口必须把鼠标消息送给Tooltip窗口这是通过给Tooptip窗口发送消息TTM_RELAYEVENT来实现的。 状态栏 状态栏类似于工具条有自己的窗口过程可以泊位、漂浮。不过习惯上状态栏都位于屏幕底部。每个状态条分成若干格Status bar panes每格从0开始编号编号作为格的索引。每一个格如同工具条的按钮一样并不是一个Windows窗口。 MFC的工具条和状态栏类 MFC使用CToolBarCtrl、CStatusBarCtrl和CToolTipCtrl窗口类分别对工具条、状态栏、Tooltip控制窗口进行了封装。 但是直接使用这些类还不是很方便。MFC提供了CToolBar、CStatusBar来处理状态栏和工具条CToolBar、CStatusBar功能更强大灵活。这两个类都派生于CControlBar。 在MFC下建议这些控制条子窗口ID介于AFX_IDW_TOOLBARFIRST(0xE800)和AFX_IDW_CONTROLBAR_LAST0Xe8FF之间。这256个ID中前32个又有其特殊性用于MFC的 打印 预览中。 CControlBar派生于CWnd类是控制条窗口类的基类它派生出CToolBar、CStatusBar、CDockBar、CDialogBar、COleResizeBar类。CControlBar实现了以下功能 和父窗口边框窗口的顶部或者底部或者其他边对齐。 可以包含子条目这些条目或者是基于HWND的子窗口或者是基于非HWND的条目。负责分配条目数组。 支持CBRS_TOP缺省控制条放在顶部CBRS_BOTTOM放在底部CBRS_NOALIGN父窗口大小变化时不重新放置控制条等几种控制风格。
支持派生类的实现。几个派生类有一定的共性或者其中两个有一定的共性这样CControlBar实现的函数一部分只适用于某个派生类一部分适用于两个或者多个派生类还有一部分适用于所有的派生类。所谓适用这里指派生类直接继承了CControlBar的实现或者覆盖了其实现但是建立在扩展其实现的基础上。类似地CControlBar的成员变量也不是为所有派生类所共同适用的。 CStatusBar和CControlBar一方面建立在CControlBar的基础之上另一方面以Windows的通用控制状态栏和 工具 条为基础。它们继承了CControlBar类的特性但是所封装的窗口句柄是相应的Windows控制窗口的句柄如同CFormView继承了CSrcollView的视类特性但是其窗口句柄是无模式对话框窗口句柄一样。 典型地如果在使用AppWizard生成应用程序时指定了要求工具条和状态栏的支持则在主边框窗口的OnCreate函数中包含一段如下的 代码 用来创建工具条、状态栏和设置一些特性。
//创建工具栏if (!m_wndToolBar.Create(this) ||!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)){TRACE0(Failed to create toolbar);return -1; // fail to create}//创建状态栏if (!m_wndStatusBar.Create(this) ||!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))){TRACE0(Failed to create status bar);return -1; // fail to create}// TODO: Remove this if you dont want tool tips or a resizeable toolbar//对工具栏设置Tooltip特征m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);//使得工具栏可以泊位在边框窗口// TODO: Delete these three lines if you dont want the toolbar to// be dockablem_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(m_wndToolBar); 工具条除了TooltipResizeableDockable特性外还可以是Floatable。应用程序可以使用CFrameWnd::SaveBarState 保存 边框窗口的控制条的有关 信息 到INI文件或者Windows Register库使用LoadBarSate从INI文件或者Register库中读取有关信息并恢复各个控制条的设置。 下文将讨论工具条等的创建、销毁从中 分析 CControlBar和派生类的关系讨论CControlBar如何实现共性如何支持派生类的特定要求派生类又如何实现自己的特定需求等。
控制窗口的创建 创建 工具 条、状态条、对话框工具栏的方法是不同的所以必须给每个派生类CToolBar、CStatusBar、CDialogBar 设计 和实现自己的窗口创建函数Create。但是它们是也是有共性的共性由CControlBar的PreCreateWindow处理。在窗口创建之后各个派生类都要进行的处理共性由CControlBar的OnCreate完成特别的处理通过派生类的OnNcCreate完成。 PreCreateWindow 首先讨论CControlBar 类的PreCreateWindow的实现。
BOOL CControlBar::PreCreateWindow(CREATESTRUCT cs){if (!CWnd::PreCreateWindow(cs))return FALSE;//修改窗口风格强制适用clipsliblings以防重复绘制cs.style | WS_CLIPSIBLINGS;//default border style translation for Win4//(you can turn off this translation by setting CBRS_BORDER_3D)if (afxData.bWin4 (m_dwStyle CBRS_BORDER_3D) 0){DWORD dwNewStyle 0;switch (m_dwStyle (CBRS_BORDER_ANY|CBRS_ALIGN_ANY)){case CBRS_LEFT: //控制条在边框窗口的左边显示dwNewStyle CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;break;case CBRS_TOP://控制条在边框窗口的顶部显示dwNewStyle CBRS_BORDER_TOP;break;case CBRS_RIGHT://控制条在边框窗口的右边显示dwNewStyle CBRS_BORDER_TOP|CBRS_BORDER_BOTTOM;break;case CBRS_BOTTOM://控制条在边框窗口的底部显示dwNewStyle CBRS_BORDER_BOTTOM;break;}// set new style if it matched one of the predefined border typesif (dwNewStyle ! 0){m_dwStyle ~(CBRS_BORDER_ANY);m_dwStyle | (dwNewStyle | CBRS_BORDER_3D);}}return TRUE;} 其中afxData是一个全局变量MFC用它来记录 系统 信息 如版本信息等。这里afxData.bWin4表示Windows版本是否高于4.0。 CToolBar的PreCreateWindow函数修改了窗口风格也修改状态栏、工具栏等的CBRS_风格。CBRS_风格的改变不会影响窗口风格。因为这些CBRS_风格被保存在成员变量m_dwStyle中。 除了上述在程序中用到的影响工具条、状态栏等显示位置的CBRS_风格外还有和泊位相关的CBRS_风格CBRS_ALIGN_LEFT、CBRS_ALIGN_RIGHT、CBRS_ALIGN_BOTTOM、CBRS_ALIGN_TOP、CBRS_ALIGN_ANY分别表示工具条可以在停泊在边框窗口的左边、右边、底部、顶部或者所有这些位置和漂浮相关的CBRS_风格CBRS_FLOAT_MULTI表示多个工具条可以漂浮在一个微型边框窗口中和Tooltips相关的CBRS_风格CBRS_TOOLTIPS和CBRS_FLYBY。
派生类如果没有特别的要求可以不覆盖PreCreateWindow函数。CStatusBar因为有更具体和特殊的风格要求所以它覆盖了PreCreateWindow。CStatusBar的覆盖实现调用了CControlBar的实现。 派生类也可以在覆盖实现中修改PreCreateWindow参数cs改变窗口风格修改m_dwStyle改变CBRS_风格。 控制条的窗口创建 CControlBar派生类实现了自己的窗口创建函数CreateCControlBar的PreCreateWindow被派生类的Create函数直接或者间接地调用。以CToolBar为例讨论窗口创建函数和创建过程。 CToolBar的窗口创建函数Create Create函数实现如下
BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID){ASSERT_VALID(pParentWnd); // must have a parentASSERT (!((dwStyle CBRS_SIZE_FIXED) (dwStyle CBRS_SIZE_DYNAMIC)));// 保存dwStyle指定的CBRS_风格m_dwStyle dwStyle;if (nID AFX_IDW_TOOLBAR)m_dwStyle | CBRS_HIDE_INPLACE;//去掉参数dwStyle包含的CBRS_风格dwStyle ~CBRS_ALL;//设置窗口风格dwStyle |CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;//初始化通用控制可以导致InitCommonControl的调用VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTLS_REG));//创建窗口将调用PreCreateWindow,OnCreate, OnNcCreate等CRect rect; rect.SetRectEmpty();if (!CWnd::Create(TOOLBARCLASSNAME, NULL, dwStyle,rect, pParentWnd, nID))return FALSE;// Note: Parent must resize itself for control bar to be resizedreturn TRUE;} 其中 Create函数的参数1表示工具条的父窗口。参数2指定窗口风格和CBRS_风格缺省值为 WS_CHILD | WS_VISIBLE | CBRS_TOP其中WS_CHILD和WS_VISIBLE是窗口风格CBRS_TOP是CBRS_风格。参数3指定工具条ID缺省值为AFX_IDW_TOOLBAR0X0E800或者59392。如果还有多个工具栏要显示在创建它们时则必须给每个工具栏指明ID。 首先Create函数把参数2dwStyle指定的窗口风格和CBRS_风格分离出来窗口风格保留在dwStyle中CBRS_风格保存到成员变量m_dwStyle中。CToolBar::PreCreateWindow将进一步修改这些风格。 接着Create函数调用了函数AfxDeferRegisterClass。它如果没有注册TOOLBARCLASSNAME表示的“窗口类”就注册该类否则返回TRUE表示已经注册。TOOLBARCLASSNAME表示的字符串是“ToolbarWindow32”即“窗口类”名称。
然后调用CWnd::Create(7个参数)使用“ToolbarWindow32”“窗口类”创建工具栏。 Create在创建窗口的过程中用MFC的标准窗口过程取代原来的窗口过程如同CFormView和CDialog窗口创建时窗口过程被取代一样并发送WM_CREATE和WM_NCCREATE消息。 至于添加向工具栏添加按钮则由函数LoadToolBar完成。在分析LoadToolBar函数之前先讨论OnCreate、OnNcCreate等函数。 处理WM_CREATE消息 CControlBar提供了消息处理函数OnCreate来处理WM_CREATE消息。
int CControlBar::OnCreate(LPCREATESTRUCT lpcs){//调用基类的实现if (CWnd::OnCreate(lpcs) -1)return -1;//针对工具栏是否有Tooltip特性if (m_dwStyle CBRS_TOOLTIPS)EnableToolTips();//得到父窗口并添加自身到其控制条列表中CFrameWnd *pFrameWnd (CFrameWnd*)GetParent();if (pFrameWnd-IsFrameWnd()){m_pDockSite pFrameWnd;m_pDockSite-AddControlBar(this);}return 0;} 如果需要支持Tooltips则OnCreate调用EnableTooltips。 m_pDockSite是CControlBar的和泊位相关的成员变量这里把它初始化为拥有工具栏的父边框窗口该边框窗口把控制条加入其控制条列表m_listControlBars中。 在处理WM_CREATE之前派生类先处理消息WM_NCCREAE。例如CToolBar覆盖了OnNcCreate函数。 处理WM_NCCREATE消息 CToolBar对WM_NCCREATE消息的处理如下
BOOL CToolBar::OnNcCreate(LPCREATESTRUCT lpCreateStruct){if (!CControlBar::OnNcCreate(lpCreateStruct))return FALSE;// if the owner was set before the toolbar was created, set it nowif (m_hWndOwner ! NULL)DefWindowProc(TB_SETPARENT, (WPARAM)m_hWndOwner, 0);DefWindowProc(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);return TRUE;} CToolBar覆盖CcontrolBar的该函数用来设置工具条的所属窗口和描述工具条按钮结构的大小这两个动作都是通过给工具条窗口发送消息来实现的。因为这些消息被送给控制窗口类的窗口过程Windows提供的来处理所以直接调用DefWindowProc省却了消息发送的过程。 在控制窗口创建之后对于工具条来说下一步就是向工具栏添加按钮。
向 工具 栏添加 按钮 通过函数LoadToolBar完成向工具栏添加按钮的任务其实现如下
BOOL CToolBar::LoadToolBar(LPCTSTR lpszResourceName){ASSERT_VALID(this);ASSERT(lpszResourceName ! NULL);//查找并确认按钮位图、字符串等资源的位置HINSTANCE hInst AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);HRSRC hRsrc ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);if (hRsrc NULL)return FALSE;//锁定资源HGLOBAL hGlobal LoadResource(hInst, hRsrc);if (hGlobal NULL)return FALSE;CToolBarData* pData (CToolBarData*)LockResource(hGlobal);if (pData NULL)return FALSE;ASSERT(pData-wVersion 1);//复制与各个位图对应的命令ID到数组pItemUINT* pItems new UINT[pData-wItemCount];for (int i 0; i pData-wItemCount; i)pItems[i] pData-items()[i];//添加按钮到工具栏指定各个按钮对应的IDBOOL bResult SetButtons(pItems, pData-wItemCount);delete[] pItems;//设置按钮的位图if (bResult){// set new sizes of the buttonsCSize sizeimage(pData-wWidth, pData-wHeight);CSize sizeButton(pData-wWidth 7, pData-wHeight 7);SetSizes(sizeButton, sizeimage);// load bitmap now that sizes are known by the toolbar controlbResult LoadBitmap(lpszResourceName);}UnlockResource(hGlobal);FreeResource(hGlobal);return bResult;} LoadToolBar函数的参数指定了资源。ToolBar资源的类型是RT_TOOLBARToolBar位图资源的类型是RT_BITMAP。 在RT_TOOLBAR类型的资源读入 内存 之后可以用CToolBarData结构描述。一个这样的结构包括了ToolBar资源的如下信息 工具条位图的版本宽度高度个数各个位图对应的命令ID。 然后LoadToolBar把这些命令ID被复制到数组pItem中根据位图宽度、高度形成按钮 尺寸 sizeButton和位图尺寸sizeimage。 接着调用SetBottons添加按钮到工具栏把各个按钮和命令ID对应起来调用SetSizes设置按钮和位图的尺寸大小调用LoadBitmap添加或者取代工具条的位图列表。这些动作都是调用工具栏“窗口类”的窗口过程完成的。例如SetButtons的实现
BOOL CToolBar::SetButtons(const UINT* lpIDArray, int nIDCount){ASSERT_VALID(this);ASSERT(nIDCount 1); // must be at least one of themASSERT(lpIDArray NULL ||AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));//首先删除 工具 条中现有的 按钮 int nCount (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);while (nCount--)VERIFY(DefWindowProc(TB_DELETEBUTTON, 0, 0));if (lpIDArray ! NULL)//命令ID数组非空{//添加新按钮TBBUTTON button ; memset(button, 0, sizeof(TBBUTTON));int iimage 0;for (int i 0; i nIDCount; i){button.fsState TBSTATE_ENABLED;if ((button.idCommand *lpIDArray) 0){//按钮之间分隔button.fsStyle TBSTYLE_SEP;//按钮之间隔8个像素button.iBitmap 8;}else{//有位图和命令ID的按钮button.fsStyle TBSTYLE_BUTTON;button.iBitmap iimage;//设置位图索引}//添加按钮if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)button))return FALSE;}}else//命令ID数组空添加空按钮{TBBUTTON button; memset(button, 0, sizeof(TBBUTTON));button.fsState TBSTATE_ENABLED;for (int i 0; i nIDCount; i){ASSERT(button.fsStyle TBSTYLE_BUTTON);if (!DefWindowProc(TB_ADDBUTTONS, 1, (LPARAM)button))return FALSE;}}//记录按钮个数到成员变量m_nCount中m_nCount (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0);//稍后放置按钮m_bDelayedButtonLayout TRUE;return TRUE;} 函数的参数1是一个数组数组的各个元素就是命令ID参数2是按钮的个数。首先SetButtons删除工具条原来的按钮然后添加新的按钮若命令ID数组非空则把每一个按钮和命令ID对应并分配位图索引否则设置空按钮并返回FALSE最后记录按钮个数。 从SetButtons的实现可以看出对工具条的所有操作都是通过工具条“窗口类”的窗口过程完成的SetSizes、LoadBitmap也是如此这里不作讨论。
状态栏和对话框 工具 栏的创建 至此 分析 了MFC创建工具条窗口的过程。对于状态栏和对话框工具栏有类似的步骤但也有不同之处。 CStatusBar的Create使用“msctls_statusbar32”“窗口类”创建状态栏窗口ID为AFX_IDW_STATUS_BAR(0XE801)然后通过成员函数SetIndictors给状态栏分格类似于给工具条添加按钮的过程它实际上是通过状态栏“窗口类”的窗口过程完成的。 CDialogBar的Create使用CreateDlg创建对话框工具栏类似于CFormView的过程。在工具栏窗口创建之后要添加到父窗口的工具栏列表中这通过CControlBar::OnCreate完成。这样创建的结果导致窗口过程使用MFC的统一的窗口过程相应“窗口类”的窗口过程也将在缺省处理中被调用这一点如同CFormView和CDialog中所描述的。在初始化对话框的时候完成了各个 控制 按钮的添加。 CStatusBar和CdialogBar都没有处理消息WM_NCCREATE。 关于CStautsBar和CDialogBar创建过程的具体实现这里不作详细讨论了。 控制条的销毁 描述了控制条的创建顺便考察其销毁的设计。 工具条、状态栏等这些控制窗口都要使用DestroyWindow来销毁所有有关操作集中由CControlBar处理。CControlBar覆盖了虚拟函数DestroyWindow、PostNcDestroy和消息处理函数OnDestroy。 当然各个派生类的虚拟析构函数被实现。如果成员变量m_bAutoDelete为TRUE则 动态 创建的MFC窗口将自动销毁。 处理控制条的位置 计算控制条位置的过程和算法 工具条等控制条是作为一个子窗口在父边框窗口内显示的。为了处理控制条的布置(Layout)首先需要计算出控制条的尺寸大小这个 工作 被委派给工具条等控制窗口自己来完成。为此CControlBar提供了两个函数来达到这个目的CalcFixLayoutCalcDynamicLayout。这两个函数都是虚拟函数。各个派生类都覆盖了这两个或者其中一个函数用来计算自身的尺寸大小。这些计算比较琐碎在此不作详细讨论。其次在父窗口位置或者大小变化时控制条的大小和位置要作相应的调整。 下面描述MFC确定或者更新工具条、状态栏等位置的步骤 1边框窗口在必要的时候调用虚拟函数RecalcLayout来重新放置它的控制条和客户窗口例如在创建窗口时、响应消息WM_SIZE时见5.3.3.5节)边框窗口的初始化。 2CFrameWnd::RecalcLayout调用CWnd的成员函数RepositionBars完成控制条窗口的重新放置。
3CWnd::RepositionBars作如下的处理 RepositionBars首先给各个控制子窗口发送SendMFC内部使用的消息WM_SIZEPARENT把窗口 客户 区矩形指针传递给它们给它们一个机会来确认自己的 尺寸 。 然后各个控制子窗口用OnSizeParent响应WM_SIZEPARENT消息ControlBar实现了消息处理函数OnSizeParent它调用CalcDynamicLayout等函数确定本窗口的大小并从客户区矩形中减去自己的尺寸。 在所有的控制子窗口处理了OnSizeParent消息之后RepositonBars利用返回的信息调用函数CalcWindowRect计算客户区窗口MDI客户窗口、View等的大小。 最后调用::EndDeferWindowPos或者::SetWindowPos放置所有的窗口控制子窗口和客户窗口。 在窗口被放置的时候发送消息WM_WINDOWPOSCHANGING和WM_WINDOWPOSCHANGED。MFC的实现中控制窗口响应了前一个消息消息处理函数是OnWindowPosChanging。CControlBar、CToolBar和CStatusBar等实现了消息处理函数OnWindowPosChanging。 上述处理过程所涉及的这些函数中RecalcLayout是CFrameWnd定义的虚拟函数RepostionBars是CWnd的成员函数CalcaWindowRect是CWnd的虚拟函数OnSizeParent是CControlBar定义的消息处理函数OnWindowPosChanging是CToolbar、CStatusBar、CDockBar等CControlBar派生类定义的消息处理函数。 下面对其中两个函数RecalcLayout和RepositionBars作一些 分析 。 CFrameWnd的虚拟函数RecalcLayout RecalcLayout的实现如下
void CFrameWnd::RecalcLayout(BOOL bNotify){//RecalcLayout是否正在被调用if (m_bInRecalcLayout)return;m_bInRecalcLayout TRUE;// clear idle flags for recalc layout if called elsewhereif (m_nIdleFlags idleNotify)bNotify TRUE;m_nIdleFlags ~(idleLayout|idleNotify);//与OLE相关的处理#ifndef _AFX_NO_OLE_SUPPORT// call the layout hook -- OLE support uses this hookif (bNotify m_pNotifyHook ! NULL)m_pNotifyHook-OnRecalcLayout();#endif//是否包含浮动(floating)控制条的边框窗口(CMiniFrameWnd类)if (GetStyle() FWS_SNAPTOBARS){//计算控制条和边框窗口的位置、尺寸并设置它们的位置CRect rect(0, 0, 32767, 32767);RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery,rect, rect, FALSE);RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra,m_rectBorder, rect, TRUE);CalcWindowRect(rect);SetWindowPos(NULL, 0, 0, rect.Width(), rect.Height(),SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);}else//是普通边框窗口则设置其所有子窗口的位置、尺寸RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST,reposExtra, m_rectBorder);//本函数处理完毕m_bInRecalcLayout FALSE;} 该函数主要的目的是调用RepositionBars函数它分两种情况来调用RepositionBars函数。一种情况是当前边框窗口为浮动控制条的包容窗口微型边框窗口时另一种情况是当前边框窗口为普通边框窗口时。
CWnd的成员函数RepositionBars RepositionBars的实现如下
void CWnd::RepositionBars(UINT nIDFirst, UINT nIDL as t, UINT nIDLeftOver,UINT nFlags, LPRECT lpRectParam, LPCRECT lpRectClient, BOOL bStretch){ASSERT(nFlags 0 || nFlags reposQuery || nFlags reposExtra);AFX_SIZEPARENTPARAMS layout;HWND hWndLeftOver NULL;layout.bStretch bStretch;layout.sizeTotal.cx layout.sizeTotal.cy 0;if (lpRectClient ! NULL)layout.rect *lpRectClient; //从参数6得到客户区else//参数lpRectClient空得到客户区域GetClientRect(layout.rect);if (nFlags ! reposQuery)//准备放置各个子窗口(layout)layout.hDWP ::BeginDeferWindowPos(8); // reasonable guesselselayout.hDWP NULL; // not actually doing layout//按一定顺序给各个控制条发送父窗口resize的消息//各个控制条窗口收到消息后从客户区中扣除自己使用的区域//并且必要的话每个控制窗口调用::DeferWindowPos//剩下的区域留给nIDLeftOver子窗口for (HWND hWndChild ::GetTopWindow(m_hWnd); hWndChild ! NULL;hWndChild ::GetNextWindow(hWndChild, GW_HWNDNEXT)){UINT nIDC _AfxGetDlgCtrlID(hWndChild);CWnd* pWnd CWnd::FromHandlePermanent(hWndChild);//如果是指定的nIDLeftOver子窗口则 保存 其窗口句柄//否则是控制条窗口给它们发送WM_SIZEPARENT消息if (nIDC nIDLeftOver)hWndLeftOver hWndChild;else if (nIDC nIDFirst nIDC nIDLast pWnd ! NULL)//如果layout-hDWP非空 OnSizeParent则将执行窗口布置的操作::SendMessage(hWndChild, WM_SIZEPARENT, 0, (LPARAM)layout);}//如果是reposQuery则得到客户区矩形返回if (nFlags reposQuery){ASSERT(lpRectParam ! NULL);if (bStretch)::CopyRect(lpRectParam, layout.rect);else{lpRectParam-left lpRectParam-top 0;lpRectParam-right layout.sizeTotal.cx;lpRectParam-bottom layout.sizeTotal.cy;}return;}//其他情况下reposDefault、reposExtra则需要执行Layout操作//处理hWndLeftOver(nIDLeftOver子窗口)if (nIDLeftOver ! 0 hWndLeftOver ! NULL){CWnd* pLeftOver CWnd::FromHandle(hWndLeftOver);// allow extra space as specified by lpRectBorderif (nFlags reposExtra){ASSERT(lpRectParam ! NULL);layout.rect.left lpRectParam-left;layout.rect.top lpRectParam-top;layout.rect.right - lpRectParam-right;layout.rect.bottom - lpRectParam-bottom;}//基于layout.rect表示的客户 尺寸 计算出窗口尺寸pLeftOver-CalcWindowRect(layout.rect);//导致函数::DeferWindowPos的调用AfxRepositionWindow(layout, hWndLeftOver, layout.rect);}//给所有的窗口设置尺寸、位置(size and layout)if (layout.hDWP NULL || !::EndDeferWindowPos(layout.hDWP))TRACE0(Warning: DeferWindowPos failed - low system resources.);} RepositionBars用来改变客户窗口中控制条的尺寸大小或者位置其中
参数1和参数2定义了需要重新放置的子窗口ID的范围一般是0到0xFFFF。 参数3指定了一个子窗口ID它拥有客户窗口剩下的空间一般是AFX_IDW_PANE_FIRST表示视的窗口ID。 参数4指定了操作类型缺省是CWnd::ReposDefault表示执行窗口放置操作参数5不会用到若取值CWnd::ReposQuery则表示尝试进行窗口放置Layout 但最后不执行这个操作只是把参数5初始化成客户区的 尺寸 大小若取值CWnd::ReposExtra则把参数5的值加到参数2表示的子窗口的客户区域并执行窗口放置操作。 参数6表示传递给函数的可用窗口客户区的尺寸如果空则使用窗口客户区尺寸。 如果执行layout操作的话该函数的核心处理就是 首先调用::BeginDeferWindowPos初始化一个Windows内部的多窗口位置结构Multiple-window - position structurehDWP 然后让各个子窗口逐个调用::DeferWindowPos更新hDWP。在调用::DeferWindowPos之前要作一个确定子窗口大小的工作。这些工作通过给各个控制子窗口发送消息WM_SIZEPARENT来完成。 控制子窗口通过函数OnSizeParent响应WM_SIZEPARENT消息先确定自己的尺寸然后如果需要进行窗口布置(WM_SIZEPARENT消息参数lParam包含了一个非空的HDWP结构lpLayout-hDWP)则OnSizeParent将调用AfxRepositionWindow函数计算本控制窗口的位置结果 保存 到hDWP中。 在所有的控制窗口尺寸确定之后剩下的留给窗口hWndLeftOver如果存在的话。确定了hWndLeftOver的大小之后调用AfxRepositionWindow函数计算其位置结果保存到hDWP中。 上面提到的函数AfxRepositionWindow间接调用了::DeferWindowPos。 最后::EndDeferWindowPos使用hDWP安排所有子窗口的位置和大小。 至于其他函数如OnSizeparent、OnWindowPosChanging、CalcWindowRect这里不作进一步的分析。 工具 条、状态栏和边框窗口的 接口 应用程序在状态栏中显示 信息 MFC内部通过给边框窗口发送消息WM_SETMESSAGESTRING、WM_POPMESSAGESTRING的方式在状态栏中显示信息。这两个消息在afxpriv.h里头定义。 WM_SETMESSAGESTRING消息表示在状态栏中显示和某个ID对应的字符串信息或者指定的字符串信息消息参数wParam指定了字符串资源ID消息参数lParam指定了字符串指针两个消息参数只有一个有用。一般一个命令ID对应了一个字符串ID对应的字符串是命令ID的说明。 文章转载自: http://www.morning.gchqy.cn.gov.cn.gchqy.cn http://www.morning.mzrqj.cn.gov.cn.mzrqj.cn http://www.morning.bygyd.cn.gov.cn.bygyd.cn http://www.morning.kpzrf.cn.gov.cn.kpzrf.cn http://www.morning.zgdnd.cn.gov.cn.zgdnd.cn http://www.morning.mhmsn.cn.gov.cn.mhmsn.cn http://www.morning.gwqkk.cn.gov.cn.gwqkk.cn http://www.morning.xbrxk.cn.gov.cn.xbrxk.cn http://www.morning.rynqh.cn.gov.cn.rynqh.cn http://www.morning.rfwrn.cn.gov.cn.rfwrn.cn http://www.morning.zffps.cn.gov.cn.zffps.cn http://www.morning.hpprx.cn.gov.cn.hpprx.cn http://www.morning.sskkf.cn.gov.cn.sskkf.cn http://www.morning.mxhgy.cn.gov.cn.mxhgy.cn http://www.morning.mqbzk.cn.gov.cn.mqbzk.cn http://www.morning.ysfj.cn.gov.cn.ysfj.cn http://www.morning.hytqt.cn.gov.cn.hytqt.cn http://www.morning.rmdwp.cn.gov.cn.rmdwp.cn http://www.morning.dkzrs.cn.gov.cn.dkzrs.cn http://www.morning.xmnlc.cn.gov.cn.xmnlc.cn http://www.morning.chjnb.cn.gov.cn.chjnb.cn http://www.morning.lbggk.cn.gov.cn.lbggk.cn http://www.morning.fpqsd.cn.gov.cn.fpqsd.cn http://www.morning.brcdf.cn.gov.cn.brcdf.cn http://www.morning.frpfk.cn.gov.cn.frpfk.cn http://www.morning.tnhmp.cn.gov.cn.tnhmp.cn http://www.morning.rhpgk.cn.gov.cn.rhpgk.cn http://www.morning.kkgbs.cn.gov.cn.kkgbs.cn http://www.morning.yllym.cn.gov.cn.yllym.cn http://www.morning.abgy8.com.gov.cn.abgy8.com http://www.morning.plfrk.cn.gov.cn.plfrk.cn http://www.morning.zkqwk.cn.gov.cn.zkqwk.cn http://www.morning.yzxhk.cn.gov.cn.yzxhk.cn http://www.morning.fdfsh.cn.gov.cn.fdfsh.cn http://www.morning.qznkn.cn.gov.cn.qznkn.cn http://www.morning.bswnf.cn.gov.cn.bswnf.cn http://www.morning.kycwt.cn.gov.cn.kycwt.cn http://www.morning.yfddl.cn.gov.cn.yfddl.cn http://www.morning.tgwfn.cn.gov.cn.tgwfn.cn http://www.morning.mlnby.cn.gov.cn.mlnby.cn http://www.morning.jqwpw.cn.gov.cn.jqwpw.cn http://www.morning.cfynn.cn.gov.cn.cfynn.cn http://www.morning.jpjxb.cn.gov.cn.jpjxb.cn http://www.morning.qlrtd.cn.gov.cn.qlrtd.cn http://www.morning.mrpqg.cn.gov.cn.mrpqg.cn http://www.morning.rydbs.cn.gov.cn.rydbs.cn http://www.morning.dtlnz.cn.gov.cn.dtlnz.cn http://www.morning.qkzdc.cn.gov.cn.qkzdc.cn http://www.morning.qczjc.cn.gov.cn.qczjc.cn http://www.morning.lbgfz.cn.gov.cn.lbgfz.cn http://www.morning.drcnf.cn.gov.cn.drcnf.cn http://www.morning.rrms.cn.gov.cn.rrms.cn http://www.morning.lssfd.cn.gov.cn.lssfd.cn http://www.morning.nhgfz.cn.gov.cn.nhgfz.cn http://www.morning.itvsee.com.gov.cn.itvsee.com http://www.morning.nfgbf.cn.gov.cn.nfgbf.cn http://www.morning.dwfzm.cn.gov.cn.dwfzm.cn http://www.morning.rtqyy.cn.gov.cn.rtqyy.cn http://www.morning.frsxt.cn.gov.cn.frsxt.cn http://www.morning.dbqcw.com.gov.cn.dbqcw.com http://www.morning.zmnyj.cn.gov.cn.zmnyj.cn http://www.morning.rbbzn.cn.gov.cn.rbbzn.cn http://www.morning.yppln.cn.gov.cn.yppln.cn http://www.morning.bsrqy.cn.gov.cn.bsrqy.cn http://www.morning.qtkdn.cn.gov.cn.qtkdn.cn http://www.morning.ckbmz.cn.gov.cn.ckbmz.cn http://www.morning.brwei.com.gov.cn.brwei.com http://www.morning.zwwhq.cn.gov.cn.zwwhq.cn http://www.morning.rcww.cn.gov.cn.rcww.cn http://www.morning.tstwx.cn.gov.cn.tstwx.cn http://www.morning.nhgfz.cn.gov.cn.nhgfz.cn http://www.morning.flqkp.cn.gov.cn.flqkp.cn http://www.morning.xnpj.cn.gov.cn.xnpj.cn http://www.morning.mtrfz.cn.gov.cn.mtrfz.cn http://www.morning.mm27.cn.gov.cn.mm27.cn http://www.morning.dfwkn.cn.gov.cn.dfwkn.cn http://www.morning.nwqyq.cn.gov.cn.nwqyq.cn http://www.morning.jpgfq.cn.gov.cn.jpgfq.cn http://www.morning.sfzwm.cn.gov.cn.sfzwm.cn http://www.morning.nkyc.cn.gov.cn.nkyc.cn