类似VC++ 5.0的工具条具有平面外观,左边带有一个“把手”,你可以通过鼠标拖动这个“把手”来移动工具条。工具条各组间带有分隔线(如图所示)。当鼠标在工具条上面移动时,工具条上的相应按钮会突出显示。本文所讨论的增强型工具条CEnhanceToolBar类由CToolBar类所派生,是CToolBar类的补充和扩展。 如果你并不在乎工具条有没有“把手”的话,要生成平面工具条是十分简单的。你只需要在CMainFrame的OnCreate()函数中添加一句话就可以(必须加在工具条生成函数之后,因为MFC在生成工具条时要清除其式样): //MainFrm.cpp int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ...... if (!m_wndToolBar.Create(this) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("Failed to create toolbar\n"); return -1; // fail to create } m_wndToolBar.ModifyStyle(0,TBSTYLE_FLAT);//设置工具条为平面格式 ...... } 如果你的计算机安装了版本为4.71.1712.3的COMCTL32.DLL(该动态库随IE 4一同发行),那就更好了,你的工具条会自动绘制分隔线的。你可以通过鼠标拖动工具条的非按钮区域来移动这种工具条。 如果你要得到更好看(更“专业”)的工具条,那么你还得跟着我一步步的做下去: 添加一个新类,本文中叫做CEnhanceToolBar类,由CToolBar类派生。 为CEnhanceToolBar类添加成员变量和函数的声明,并且根据你的需要设置其属性为public/protected/private。 //EnhanceToolBar.h // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEnhanceToolBar) //按钮状态变化时调用此函数 virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); //}}AFX_VIRTUAL // Implementation public: void DrawGrip(CWindowDC *pDC, CRect& rectWindow);//“把手”绘制函数 void EraseNonClient();//擦除非客户区 void DrawSpace();//分隔线绘制函数 void RedrawBackground();//背景重绘函数 private: int ButtonNumber;//工具条的按钮数(包括分隔线) COLORREF HiLight, Shadow;//3D控件的加亮色和阴影色 添加成员函数的定义: //EnhanceToolBar.cpp void CEnhanceToolBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler) {//按钮状态变化时调用此函数 static CUIntArray Styles; int Index; UINT dwStyle; for (Index = 0; Index <buttonnumber; Index++) { dwStyle = GetButtonStyle(Index); Styles.SetAtGrow(Index,dwStyle);//保存按钮的式样 } CToolBar::OnUpdateCmdUI(pTarget,bDisableIfNoHndler);//调用基类的处理函数 for (Index = 0; Index <buttonnumber; Index++) {//设置选中的按钮(checked button)为按下的状态 dwStyle = GetButtonStyle(Index); if (dwStyle & TBBS_DISABLED) return;//如果按钮为禁用状态,则返回(避免闪烁) if (dwStyle & TBBS_CHECKBOX) { if (dwStyle & TBBS_CHECKED) dwStyle |= TBBS_PRESSED; else dwStyle &= ~TBBS_PRESSED; SetButtonStyle(Index,dwStyle);//设置按钮的式样 } } //检查按钮的式样是否改变(按下或释放) for (Index = 0; Index <buttonnumber; Index++) { dwStyle = GetButtonStyle(Index); if (Styles[Index] != dwStyle) { RedrawBackground();//重新绘制背景 Invalidate();//重新绘制整个工具条 break;//已更新整个工具条,因此没必要继续循环 } } } void CEnhanceToolBar::DrawGrip(CWindowDC *pDC, CRect& rectWindow) {//绘制把手 if (IsFloating())//如果工具条是浮动状态,则不绘制“把手” return; CRect GripRect = rectWindow;//得到把手的矩形区域 GripRect.DeflateRect(1,1);//矩形区域的各边向中心靠近一个像素 if (m_dwStyle & CBRS_ORIENT_HORZ)//如果工具条为水平状态,“把手”在左边 { GripRect.right = GripRect.left + 3;//绘制第一条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); GripRect.OffsetRect(4,0);//绘制第二条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); } else//如果工具条为垂直状态,“把手”在顶部 { GripRect.bottom = GripRect.top + 3;//绘制第一条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); GripRect.OffsetRect(0,4);//绘制第二条隆起的棱 pDC->Draw3dRect(GripRect, HiLight, Shadow); } } void CEnhanceToolBar::DrawSpace() {//绘制分隔线 CClientDC dc(this); for (int Index = 0; Index <buttonnumber; Index++) { UINT dwStyle = GetButtonStyle(Index);//获得按钮的类型 if (dwStyle & TBBS_SEPARATOR)//如果是分隔线 { CRect rect; GetItemRect(Index,rect);//获得矩形区域 if (m_dwStyle & CBRS_ORIENT_HORZ)//工具条为水平时分隔线为垂直 { int w = rect.Width(); rect.DeflateRect((w-2)/2,0);//将矩形缩减为2~3个像素宽 dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线 } else//分隔线为水平 { rect.left = rect.left - m_sizeButton.cx; rect.right = rect.left + m_sizeButton.cx; rect.top = rect.bottom+1; rect.bottom = rect.top+3; int h = rect.Height(); rect.DeflateRect(0,(h-2)/2);//将矩形缩减为2~3个像素高 dc.Draw3dRect(rect, Shadow, HiLight);//绘制分隔线 } } } } void CEnhanceToolBar::EraseNonClient() {//擦除非用户区 CWindowDC dc(this); CRect rectClient; GetClientRect(rectClient); CRect rectWindow; GetWindowRect(rectWindow); ScreenToClient(rectWindow); rectClient.OffsetRect(-rectWindow.left, -rectWindow.top); dc.ExcludeClipRect(rectClient); // 绘制非用户区的边界 rectWindow.OffsetRect(-rectWindow.left, -rectWindow.top); DrawBorders(&dc, rectWindow); // 擦除非绘制部分 dc.IntersectClipRect(rectWindow); SendMessage(WM_ERASEBKGND, (WPARAM)dc.m_hDC); DrawGrip(&dc, rectWindow); //绘制“把手” } 由于平面工具条是透明的,所以当改变尺寸和移动时(例如当拖动工具条时)就需要重绘背景。同样,当按钮状态改变时(按下或释放)也需要进行这种操作。 void CEnhanceToolBar::RedrawBackground() {//重新绘制背景 CWnd* pParent = GetParent();//获得父窗口指针 if (pParent) { CRect drawrect,rect; GetWindowRect(&rect);//获得工具条矩形区域 drawrect = rect; pParent->ScreenToClient(&drawrect);//转换为父窗口坐标 pParent->InvalidateRect(&drawrect);//重绘矩形区域 //绘制父窗口的其他工具条 for (CWnd* pSibling = pParent->GetWindow(GW_CHILD);pSibling; pSibling = pSibling->GetNextWindow(GW_HWNDNEXT)) { if (pSibling == this) continue; drawrect = rect; pSibling->ScreenToClient(&drawrect);//兄弟窗口的坐标 pSibling->InvalidateRect(&drawrect);//重绘矩形区域 } } } 利用ClassWizard给为CEnhanceToolBar类添加消息映射: //EnhanceToolBar.h //{{AFX_MSG(CEnhanceToolBar) afx_msg void OnPaint(); afx_msg void OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp); afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); //}}AFX_MSG //EnhanceToolBar.cpp BEGIN_MESSAGE_MAP(CEnhanceToolBar, CToolBar) //{{AFX_MSG_MAP(CEnhanceToolBar) ON_WM_PAINT() ON_WM_NCCALCSIZE() ON_WM_WINDOWPOSCHANGING() //}}AFX_MSG_MAP END_MESSAGE_MAP() 为消息映射函数添代码: void CEnhanceToolBar::OnPaint() { CToolBar::OnPaint();//绘制标准工具条 EraseNonClient();//擦除背景 DrawSpace();//绘制立体分隔线 } void CEnhanceToolBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp) {// 计算非用户区域,用于调整“把手” CToolBar::OnNcCalcSize(bCalcValidRects,lpncsp); if (IsFloating())//如果工具条是浮动状态,则不绘制“把手” return; if (m_dwStyle & CBRS_ORIENT_HORZ)//如果工具条为水平状态,“把手”在左边 { lpncsp->rgrc[0].left += 2; lpncsp->rgrc[0].right += 2; } else//如果工具条为垂直状态,“把手”在顶部 { lpncsp->rgrc[0].top += 4; lpncsp->rgrc[0].bottom += 4; } } void CEnhanceToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos) {//当尺寸、位置或Z方向次序变化时,程序框架调用此成员函数 CToolBar::OnWindowPosChanging(lpwndpos); RedrawBackground();//重新绘制背景 } 编写构造函数,加入下面的代码: CEnhanceToolBar::CEnhanceToolBar() { HiLight = ::GetSysColor(COLOR_3DHILIGHT);//获得3D控件的加亮色 Shadow = ::GetSysColor(COLOR_3DSHADOW);//获得3D控件的阴影色 //获得工具条的按钮数(包括分隔线) ButtonNumber = (int)DefWindowProc(TB_BUTTONCOUNT, 0, 0); } 现在编译运行,很COOL的工具条出现了,体验一下成功的感觉吧! 备注 关于工具条的其他格式,请参考COMMCRTL.H #define TBSTYLE_TOOLTIPS 0x0100 #define TBSTYLE_WRAPABLE 0x0200 #define TBSTYLE_ALTDRAG 0x0400 #define TBSTYLE_FLAT 0x0800...... 如果你的计算机安装了版本为4.71.1712.3的COMCTL32.DLL(随IE 4一同发行),那么你不需要添加下列的函数,是不是感觉更简单了? void DrawSpace();//分隔线绘制函数 void RedrawBackground();//背景重绘函数 virtual void OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler); void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos); 如何在工具条的按钮中间加入一个分隔线呢?很简单,使用资源编辑器打开应用的工具条,拖动一个按钮使其与上一个按钮离开一定距离,松开鼠标就可以了。 已知的BUG 拖动工具条使之成为垂直停泊工具条,再拖动它使之成为浮动工具条,再拖动它使之成为水平停泊工具条时,“把手”的一部分会被遮住。 如果你的计算机安装了版本为4.71.1712.3的COMCTL32.DLL(随IE 4一同发行),那么当工具条为垂直或长度超过一行需要换行时,会出现工具条的底边被剪切的情况。 |