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

📄 mfc.txt

📁 MFC工具条和状态栏 Windows控制窗口
💻 TXT
📖 第 1 页 / 共 4 页
字号:

MFC工具条和状态栏 


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_LAST(0Xe8FF)之间。这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\n");

return -1; // fail to create

}

//创建状态栏

if (!m_wndStatusBar.Create(this) ||

!m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))

{

TRACE0("Failed to create status bar\n");

return -1; // fail to create

}


// TODO: Remove this if you don't 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 don't want the toolbar to

// be dockable

m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_wndToolBar);


工具条除了Tooltip,Resizeable,Dockable特性外,还可以是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 types

if (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派生类实现了自己的窗口创建函数Create,CControlBar的PreCreateWindow被派生类的Create函数直接或者间接地调用。以CToolBar为例讨论窗口创建函数和创建过程。


CToolBar的窗口创建函数Create 

Create函数实现如下:

BOOL CToolBar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)

{

ASSERT_VALID(pParentWnd); // must have a parent

ASSERT (!((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 resized


return TRUE;

}

其中:

Create函数的参数1表示工具条的父窗口。参数2指定窗口风格和CBRS_风格,缺省值为 WS_CHILD | WS_VISIBLE | CBRS_TOP,其中WS_CHILD和WS_VISIBLE是窗口风格,CBRS_TOP是CBRS_风格。参数3指定工具条ID,缺省值为AFX_IDW_TOOLBAR(0X0E800或者59392)。如果还有多个工具栏要显示,在创建它们时则必须给每个工具栏指明ID。

首先,Create函数把参数2(dwStyle)指定的窗口风格和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 now

if (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到数组pItem

UINT* pItems = new UINT[pData->wItemCount];

for (int i = 0; i < pData->wItemCount; i++)

⌨️ 快捷键说明

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