📄 0501006.htm
字号:
align=justify>正常工具条中的按钮具有黑色的边线,使按钮凹凸感更强烈,但在平面工具条中的这种按钮并不美观,所以应省略黑色边线部分,并且必须使用系统的API函数GetSysColor函数来取得边线颜色,以便系统改变颜色时按钮边线也随之改变,同时由于凹凸按钮边线画法完全相同,只是颜色相反,所以两者完全可由这个函数来实现;</P>
<P align=justify>②画分隔线函数OnDrawSep()</P>
<P align=justify>画分隔线时应遍历每个按钮,来取得分隔线的位置,并且利用客户区域文本描述表就可实现,只需画亮暗两条线就可实现;</P>
<P align=justify>③画把手函数OnDrawGripper()</P>
<P
align=justify>画把手时应使用整个窗口的文本描述表,因为客户区域描述表不能在窗口的非客户区域画线,而且还必须判断按钮是否以多行多列方式排列,根据不同的排列方式画水平或垂直把手,同时还要实现画关闭按钮功能,以和VC++5
等界面工具栏功能完全相同,另外还要判断工具栏是否为子窗口状态,以确定是否画把手和关闭按钮;</P>
<P align=justify>④删除按钮边线函数OnEraseBorder()</P>
<P
align=justify>函数用于消除系统所绘按钮凹凸边线,使按钮具有平面效果,也必须利用系统的API函数GetSysColor函数来取得系统颜色,以保证系统改变颜色时能够正常消除按钮边线;</P>
<P align=justify>⑤实现平面工具栏所有功能函数OnDrawBorders()</P>
<P
align=justify>在该函数中应特别注意对按钮分隔符判断、按钮凹凸状态判断、鼠标左键按下后按钮凹凸状态判断、删除系统所画按钮边线判断判断和按下鼠标左键并移动鼠标按钮的凹凸状态判断等,并需要利用工具条控制取得对工具栏的引用;</P>
<P align=justify>⑥工具条更新功能函数OnPaint()</P>
<P align=justify>在这个函数中应注意对原系统更新功能函数的调用,以实现动态提示和按钮图标的显示等功能;</P>
<P align=justify>⑦鼠标左键按下功能函数OnLButtonDown()</P>
<P
align=justify>该函数中除需要调用原系统鼠标左键按下功能函数,以实现消息的发送等功能外,还需要设置鼠标左键按下标志并记录按下按钮的位置,以便程序正确判断按钮的凹凸状态;</P>
<P align=justify>⑧鼠标左键释放功能函数OnLButtonDown()</P>
<P
align=justify>该函数中除需要调用原系统鼠标左键释放功能函数,以实现按钮执行消息的发送等功能外,还需要设置鼠标左键释放标志,以便程序正确判断按钮的凹凸状态,此外还应重绘按钮凹下状态以使按钮功能执行时按钮应处于凹下状态,来保证工具栏按钮与其它高级应用程序实现的功能完全相同;</P>
<P align=justify>⑨鼠标移动功能函数OnMouseMove()</P>
<P
align=justify>该函数中应记录鼠标左键按下状态标志,并在鼠标移动到按钮上和鼠标左键按下时设置鼠标输入焦点,来保证平面工具条在鼠标移动过程中的正常凸起状态和鼠标点击按钮后对按钮状态的控制,如利用这一点可实现鼠标点击按钮后按钮下凹,不释放鼠标并移动到任何位置时按钮凸起,重新移动到按钮上按钮仍下凹,这些全是控制鼠标焦点的功能,并及时释放鼠标输入焦点;</P>
<P align=justify>⑩背景重绘等函数OnNcPaint()</P>
<P
align=justify>背景重绘函数是用来防止一个工具条被切换显示状态后,另一个工具栏中的把手和关闭按钮等消失,这在鼠标反复双击排序后工具条非客户区域时,另一个排序后工具栏就会出现的现象;另外函数SetState()用来设置工具条左边界和状态,以便为画把手和关闭按钮调整客户区域并提供绘图状态。</P>
<P align=justify>此外,还有鼠标移动到把手上光标改变形状和关闭按钮功能,由于篇幅所限这里从略,有兴趣的读者完全可以自己实现。</P>
<P align=justify>4、工具条的停靠位置</P>
<P align=justify>(1)标准工具条的停靠位置</P>
<P align=justify>工具条类CToolBar是控制条类CControlBar
的派生类,其显示的初始停靠位置是通过调用继承的函数CControlBar::EnableDocking(DWORD
dwStyle)来确定的,其参数dwStyle用来指定停靠具体位置,与本文有关的风格如下,其余请参阅VC5的联机帮助:</P>
<P align=justify>CBRS_ALIGN_TOP 工具条停靠在客户区域顶部</P>
<P align=justify>CBRS_ALIGN_BOTTOM 工具条停靠在客户区域底部</P>
<P align=justify>CBRS_ALIGN_LEFT 工具条停靠在客户区域左边</P>
<P align=justify>CBRS_ALIGN_RIGHT 工具条停靠在客户区域右边</P>
<P align=justify>CBRS_ALIGN_ANY 工具条停靠在客户区域任何位置</P>
<P align=justify>利用应用程序向导AppWizard
生成的应用程序,其默认的停靠位置为CBRS_ALIGN_ANY,即允许停靠在客户区域的任何边,正常显示时为靠近客户区域的顶部:EnableDocking(CBRS_ALIGN_ANY)
,详见上述的工具栏建立函数ONCREATE()。</P>
<P align=justify>应用程序的单文档和多文档的窗口框架类均为CFrameWnd 的派生类,其指定工具条的停靠位置均是通过调用继承的函数
CFrameWnd::EnableDocking(DWORD
dwDockStyle)来实现的,其可选的参数除上述五种之外,还增加了CBRS_FLOAT_MULTI参数,这个参数主要是为设计浮动工具条而增加的,其用来确定一个框架窗口中允许存在多个浮动工具栏。同样利用应用程序向导AppWizard
生成的应用程序,其默认的停靠位置也是CBRS_ALIGN_ANY,即允许停靠在框架窗口的任何边,正常显示时为靠近框架窗口的顶部,即为EnableDocking(CBRS_ALIGN_ANY),详见上述的工具条建立函数ONCREATE()。</P>
<P align=justify>(2)浮动工具条的停靠位置</P>
<P align=justify>当一个框架窗口中存在多个浮动工具条时,需要利用函数void DockControlBar(CControlBar
*pBar,UINT nDockBarID=0,LPCRECT lpRect=
NULL)来确定要控制停靠位置的工具条,它也是CFrameWnd类的成员函数,其中参数pBar用来指向被控制停靠位置的工具条对象,参数nDockBarID用来确定工具条停靠在框架窗口的哪条边上,取值为:</P>
<P align=justify>AFX_IDW_DOCKBAR_TOP 工具条停靠在框架窗口的顶部</P>
<P align=justify>AFX_IDW_DOCKBAR_BOTTOM 工具条停靠在框架窗口的底部</P>
<P align=justify>AFX_IDW_DOCKBAR_LEFT 工具条停靠在框架窗口的左边</P>
<P align=justify>AFX_IDW_DOCKBAR_RIGHT 工具条停靠在框架窗口的右边</P>
<P align=justify>如果参数nDockBarID取值为0,则工具条可以停靠在框架窗口中的任何一个可停靠的边上,其默认位置为顶部。</P>
<P align=justify>(3)工具条的连接停靠方法</P>
<P
align=justify>在很多应用程序中都存在将多个工具条同时停靠在某窗口的某一条边上的同一工具条窗口中的情况,利用上述工具条控制函数DockControlBar的lpRect参数,通过控制工具条的停靠矩形区域来实现这个功能,如笔者实现的函数如下:</P>
<P align=justify>①在主程序实现文件MainFrm.h中增加函数定义</P>
<P align=justify>public:</P>
<P align=justify>void DockControlBarLeftOf(CToolBar* Bar,CToolBar* LeftOf);</P>
<P align=justify>②在主程序实现文件MainFrm.cpp中增加如下函数</P>
<P align=justify>void CMainFrame::DockControlBarLeftOf(</P>
<P align=justify>CToolBar* Bar,CToolBar* LeftOf)</P>
<P align=justify>{ //设置工具条停靠在同一边窗口中</P>
<P align=justify>CRect rect;</P>
<P align=justify>DWORD dw;</P>
<P align=justify>UINT n;</P>
<P align=justify>RecalcLayout();//重新显示</P>
<P align=justify>LeftOf->GetWindowRect(&rect);</P>
<P align=justify>rect.OffsetRect(1,0);//设置偏移值以停靠在同一窗口中</P>
<P align=justify>dw=LeftOf->GetBarStyle();</P>
<P align=justify>n=0;</P>
<P align=justify>n=(dw&CBRS_ALIGN_TOP)?AFX_IDW_DOCKBAR_TOP:n;</P>
<P
align=justify>n=(dw&CBRS_ALIGN_BOTTOM&&n==0)?AFX_IDW_DOCKBAR_BOTTOM:n;</P>
<P
align=justify>n=(dw&CBRS_ALIGN_LEFT&&n==0)?AFX_IDW_DOCKBAR_LEFT:n;</P>
<P
align=justify>n=(dw&CBRS_ALIGN_RIGHT&&n==0)?AFX_IDW_DOCKBAR_RIGHT:n;</P>
<P align=justify>DockControlBar(Bar,n,&rect);</P>
<P align=justify>}</P>
<P
align=justify>在这个函数中应注意对RecalcLayout()函数和OffsetRect()函数的调用,前一个函数用来重新显示被调整的客户区和工具条,后一个函数用来重新确定矩形区域,这相当于用鼠标将第二个工具条拖动到前一个工具条上。</P>
<P
align=justify>③修改应用程序建立函数OnCreate()函数中的相应DockControlBar()函数为DoctControlBarOf()函数,并正确设置工具条指针,见工具条的建立技巧中的有关函数。</P>
<P align=justify>(4)定制工具条的顶部停靠控制</P>
<P
align=justify>另一种工具条的停靠位置是定制工具条的停靠位置,如具有通用控制功能工具条的停靠位置,这主要实现左侧定制工具条与顶部工具条之间的位置关系。其实现方法如下:</P>
<P align=justify>①打开菜单资源增加顶部位置控制菜单项IDD_DLGBARTOP;</P>
<P align=justify>②在实现文件MainFrm.h中增加成员控制变量m_bDialogTop;</P>
<P align=justify>BOOL m_bDialogTop;</P>
<P align=justify>并在构造函数中为其设置初始值;</P>
<P align=justify>③利用类向导函数为菜单项设置响应函数;</P>
<P align=justify>④在实现文件MainFrm.cpp中完善消息映射函数。</P>
<P align=justify>void CMainFrame::OnButtonDlgbartop()</P>
<P align=justify>{ //定制工具条顶部位置控制函数</P>
<P align=justify>if (m_bDialogTop) m_wndDlgBar.SetWindowPos(</P>
<P align=justify>&m_wndStatusBar,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);</P>
<P align=justify>//其它工具条停靠在最顶部,该工具条停靠其下</P>
<P align=justify>else m_wndDlgBar.SetWindowPos(&wndTop,0,0,0,0,</P>
<P align=justify>SWP_NOSIZE|SWP_NOMOVE);//停靠在最顶部</P>
<P align=justify>RecalcLayout(); //重新显示窗口</P>
<P align=justify>m_bDialogTop=!m_bDialogTop;//改变变量标志</P>
<P align=justify>}</P>
<P align=justify>void CMainFrame::OnUpdateButtonDlgbartop(CCmdUI* pCmdUI)</P>
<P align=justify>{ //设置菜单项检查状态</P>
<P align=justify>pCmdUI->SetCheck(m_bDialogTop);</P>
<P align=justify>}</P>
<P align=justify>5、工具条按钮的排序方法</P>
<P align=justify>利用应用程序向导AppWizard
生成的应用程序工具条,其按钮均为单行水平排列的,这在实际程序开发时既不美观又不实用,很多大型应用程序等界面中的工具条都采用多行多列的排序方式,要在自己的应用程序中实现这种排列方式,应按下述方法在派生类中控制:</P>
<P align=justify>(1)在TestToolBar.h中增加函数定义和成员变量控制</P>
<P align=justify>class CTestToolBar : public CToolBar</P>
<P align=justify>{......//其它代码</P>
<P align=justify>public:</P>
<P align=justify>CTestToolBar(); //在构造函数后增加下一行</P>
<P align=justify>void SetColumns(UINT nColumns);//增加列控制</P>
<P align=justify>......//其它代码</P>
<P align=justify>protected: //增加成员变量</P>
<P align=justify>UINT m_nColumns; //工具条列按钮数</P>
<P align=justify>......//其它代码</P>
<P align=justify>}</P>
<P align=justify>(2)在TestToolBar.cpp中增加变量初始化和函数</P>
<P align=justify>CTestToolBar::CTestToolBar()</P>
<P align=justify>{ //在构造函数中初始化变量</P>
<P align=justify>m_nColumns=0; //工具条按钮列数</P>
<P align=justify>......//其它代码</P>
<P align=justify>}</P>
<P align=justify>void CTestToolBar::SetColumns(UINT nColumns)</P>
<P align=justify>{ //设置按钮排列格式</P>
<P align=justify>m_nColumns=nColumns;//列数</P>
<P align=justify>int nCount=GetToolBarCtrl().GetButtonCount();//按钮数</P>
<P align=justify>for(int i=0;i<nCount;i++){</P>
<P align=justify>UINT nStyle=GetButtonStyle(i);//按钮风格</P>
<P align=justify>BOOL bWrap=(((i+1)%nColumns)==0);</P>
<P align=justify>if(bWrap) nStyle|=TBBS_WRAPPED;//设置换行</P>
<P align=justify>else nStyle&=~TBBS_WRAPPED;//不换行</P>
<P align=justify>SetButtonStyle(i,nStyle);//设置风格</P>
<P align=justify>}</P>
<P align=justify>Invalidate();//窗口更新</P>
<P align=justify>GetParentFrame()->RecalcLayout();//工具栏状态更新</P>
<P align=justify>}</P>
<P
align=justify>(3)在应用程序建立函数OnCreate()中为相应的工具条增加列控制功能,并注意对保存和恢复工具条状态函数的列控制参数处理,请参阅工具条建立技巧和状态保存与恢复中的有关函数,重新编译并执行应用程序就可以看到多行多列的工具条。</P>
<P align=justify>6、工具条的消息映射技巧</P>
<P align=justify>如果工具条上的按钮都存在对应的菜单命令,那么可以直接利用类向导ClassWizard
进行命令消息的映射,否则必须通过手工的方法来进行命令按钮的消息映射。由于同一工具栏的命令按钮都存在相类似的功能,所以只要注意将同一工具条中的命令按钮ID值设置成连续值,就可以利用范围命令处理机制统一对所有按钮命令进行管理,即所有命令按钮的消息可以在同一命令消息处理函数和更新命令消息处理函数中进行管理,这样不但结构紧凑而且维护特别方便。鉴于类向导ClassWizard
不支持范围命令处理功能,所以其消息映射机制必须通过手工方式来完成。按钮命令消息既可以在框架窗口中映射,也可以在文档和视图中完成映射,由于文档对象通常用来管理程序中的数据部分,并且在多文档应用程序(MDI)
中,一个文档可能有多个视图与之关联,因此把工具栏中的命令按钮消息映射在文档中比较合适些。其实现步骤如下:</P>
<P align=justify>(1)在文档实现文件CToolDoc.h中增加函数定义和数据成员:</P>
<P align=justify>class CCTOOLDoc : public CDocument</P>
<P align=justify>{......//其它代码</P>
<P align=justify>protected:</P>
<P align=justify>UINT iPosition; //命令按钮消息位置</P>
<P align=justify>......//其它代码</P>
<P align=justify>protected:</P>
<P align=justify>//{{AFX_MSG(CCTOOLDoc)</P>
<P align=justify>afx_msg void OnTool(UINT nID);//命令消息映射</P>
<P align=justify>afx_msg void OnUpdateTool(CCmdUI* pCmdUI);//更新消息映射</P>
<P align=justify>//}}AFX_MSG</P>
<P align=justify>DECLARE_MESSAGE_MAP()</P>
<P align=justify>......//其它代码</P>
<P align=justify>}</P>
<P align=justify>(2)在文档实现文件CToolDoc.cpp中进行消息映射</P>
<P align=justify>BEGIN_MESSAGE_MAP(CCTOOLDoc,CDocument)</P>
<P align=justify>//{{AFX_MSG_MAP(CCTOOLDoc)</P>
<P align=justify>ON_COMMAND_RANGE(ID_BUTTON_LINE,</P>
<P align=justify>ID_BUTTON_SORT,OnTool);</P>
<P align=justify>ON_UPDATE_COMMAND_UI_RANGE(ID_BUTTON_LINE,</P>
<P align=justify>ID_BUTTON_SORT,OnUpdateTool);</P>
<P align=justify>//}}AFX_MSG_MAP</P>
<P align=justify>END_MESSAGE_MAP()</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -