网页功能: 加入收藏 设为首页 网站搜索  
VC++ 5.0式样的工具条
发表日期:2003-05-28作者:[] 出处:  

类似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一同发行),那么当工具条为垂直或长度超过一行需要换行时,会出现工具条的底边被剪切的情况。

我来说两句】 【加入收藏】 【返加顶部】 【打印本页】 【关闭窗口
中搜索 VC++ 5.0式样的工具条
本类热点文章
  VC中DDB与DIB位图编程全攻略
  VC中列表视图控件的使用
  实战静态拆分视图
  让你的软件界面更漂亮
  C++编程中Windows图像编程概要
  在任务栏状态区显示应用程序图标
  仿Explorer的目录树视图类
  VC学习:IP地址控件小技巧
  在状态条上显示当前时间
  VC++ 5.0式样的工具条
  使用拖放的简单方法
  VC下编程实现3D文字
最新分类信息我要发布 
最新招聘信息

关于我们 / 合作推广 / 给我留言 / 版权举报 / 意见建议 / 广告投放  
Copyright ©2003-2019 Lihuasoft.net webmaster(at)lihuasoft.net
网站编程QQ群   京ICP备05001064号 页面生成时间:0.00417