VC.NET界面编程中关于的ToolBar(工具栏)的编程应用(一)

来源:互联网 发布:淘宝宽屏代码 编辑:程序博客网 时间:2024/06/05 22:42
2008/07/01 19:21
一、ToolBar的添加:
  首先是在VC的资源编辑器中添加ToolBar的各项资源包括按钮、按钮图片,然后为加入的ToolBar及其按钮定义属性包括名称、点击按钮后所调用的函数名。
  然后要在程序的主框架CPP文件(实现文件)中加载我们刚才添加好的工具栏ToolBar资源,并使其在程序的主框架中显示,如果你已经明白程序框架的工作原理,那么你会知道,以下代码应该加到MainFrame.CPP文件中,如果是加在MDI多文档视图程序的子窗口内就应该把代码加到ChildFrame.CPP文件中。通常我们是通过应用程序向导来建立程序的初始框架的,所以会在程序框架的实现文件中看到下面用来加载显示ToolBar的代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
   return -1;
//从这里开始是加载工具栏的代码,里面有加载的样式
//如果你不想要工具栏的把手可以删除 | CBRS_GRIPPER
//去掉|WS_VISIBLE表示隐藏工具栏
//其它风格可以自己查阅MSDN
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | CBRS_TOP
   | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
   !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
//IDR_MAINFRAME是我建立的ToolBar的名称

{
   TRACE0("未能创建工具栏 ");
   return -1;       // 未能创建
}
//这里我建立了第二个名为IDR_MAINFRAME1的工具栏
    if (!m_wndToolBar1.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
   | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
   !m_wndToolBar1.LoadToolBar(IDR_MAINFRAME1))
{
   TRACE0("未能创建工具栏 ");
   return -1;       // 未能创建
}
if (!m_wndStatusBar.Create(this) ||
   !m_wndStatusBar.SetIndicators(indicators,
     sizeof(indicators)/sizeof(UINT)))
{
   TRACE0("未能创建状态栏 ");
   return -1;       // 未能创建
}
// TODO: 如果不需要工具栏可停靠,则删除这三行
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
m_wndToolBar1.EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar1);
return 0;
}
  通过在主框架实现文件中添加代码就能实现工具栏的创建,如果你是初学者,那么还得知道必需在主框架的头文件如:MainFrame.h中添加如下代码:
protected:   // 控件条嵌入成员
CStatusBar   m_wndStatusBar; //定义一个状态栏数据类
CToolBar     m_wndToolBar; //定义一个工具栏数据类
CToolBar m_wndToolBar1;  //定义一个工具栏数据类
// 生成的消息映射函数
protected:
//发送一条OnCreate消息用来通知主框架建立工具栏
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
 明白了上面的原理你就可以在MDI程序的子窗口中添加你想要的ToolBar了。
二、使工具栏上的按钮运作
  当加入工具栏时设置好按钮的名称如:ID_BUTTON,然后在Prompt一项中加入点击按钮时要响应的函数如:OnAddButton,这里的函数可以是程序内部的,也可以是自定的。如果是自定的,像上面的OnAddButton,那么应该到Class View(类视图)中选中主框架类(CMainFrame),右击鼠标选择ADD为其添加一个Function(函数),我上面定义的是一个void型的函数。
  在主框架CPP文件中的消息响应宏中加入以下代码:
  
  ON_COMMAND(ID_BUTTON,OnAddButton)
COMMAND是一个命令消息,表示按下工具栏上名为ID_BUTTON的按钮时执行OnAddButton函数。
三、工具栏中动态增加一个按钮
  上网查到的都是一些零碎的资料,对我一个初学来说整理出来可真不是一件容易的事。
  
  常使用Photoshop和DreamWeaver,对它们的工具栏很好奇,因为它们的工具栏是可以动态变换的,像Photoshop中,每一个绘图工具都相对应于一个工具栏。
  经过研究后有两种方法可以实现,第一种是程序初运行时就加载多个工具栏,然后只显示一个,其它的由运行时的需要显示或者隐藏。这种方法在MDI程序中有很大的缺陷,因为每隐藏或者显示一次工具栏,整个程序窗口都会闪一次,于是找到了第二种方法,动态添加与删除工具栏上的按钮。
  现在我用上面已经建立的工具栏和OnAddButton函数来实现按下工具栏上的名为ID_BUTTON按钮后调用OnAddButton函数来添加一个按钮,下面是要加入的代码:
void CMainFrame::OnAddButton(void)
{
//调整工具栏的控制类
CToolBarCtrl& ctrl=m_wndToolBar1.GetToolBarCtrl();
//为新建的按钮调入一张名为IDB_BITMAP1的位图
int bmindex=ctrl.AddBitmap(1,IDB_BITMAP1);
//定义一个工具栏按钮对象
TBBUTTON   bt;
ZeroMemory(&bt,sizeof(TBBUTTON));
//定义新按钮的初始状态,激活或者是非激活
bt.fsState|=TBSTATE_ENABLED;
//定义加入的按钮样式
bt.fsStyle|=TBSTYLE_BUTTON;
//把刚才调入的位图加载到按钮上
bt.iBitmap=bmindex;
//为按钮定义名称
bt.idCommand=ID_BUTTONCOOL;
//执行添加
ASSERT(ctrl.AddButtons(1,&bt));
//刷新添加按钮后的工具栏
RecalcLayout();
CFrameWnd::ShowControlBar(&m_wndToolBar1,TRUE,TRUE);
}
  执行上面的代码你会发现在VS2005中会报错,说是ID_BUTTONCOOL未定义,这是因为运行程序后,在建立程序框架时的图片如:按钮图片等都是从资源文件resource.cpp中加载的,而每一个资源相对应于一个事先就定义好的常量,如果程序加载代码时未发现相应资源名就会报错了。打开resource.h你会发现在文件里定义了我们刚才添加的按钮名称以及其它资源名,那么我们只要在这里为要新建的工具栏按钮预定义一个名称就行了,在里面打上代码:
//32773为资源名的序号,只要程序里还没有就可随便加一个
#define ID_BUTTONCOOL                    32773
  通过上面的代码我们就实现了在工具栏中动态添加一个按钮,现在我们还需要做一件事。因为按钮是添加上去了,但让它工作起来却是件麻烦事。
  完成这个工作很容易,在资源视图中你会看见String Table这一资源项,在这里面有对程序内所有字符串资源的定义,双击它进入编辑,在里面加入刚才我们定义的ID_BUTTONCOOL,Value填 32773 Caption填要调用的函数名如:OnDeleteButton,这时再到主框架的消息响应宏中加入响应代码:
  ON_COMMAND(ID_BUTTONCOOL,OnDeleteButton)
  这样,新增加的按钮就可以正常使用了。
四、在工具栏上动态删除一个按钮
  因为本人太菜,所以暂时还没找到可以删除指定按钮的方法,在这里只说说动态的删除按钮动作的实现方法。
  上面已经添加了OnAddButton函数和点击新增按钮时的执行函数,现在再按照上面步骤再在主框架类中添加一个删除按钮的函数OnDeleteButton,然后在主框架CPP文件中的OnDeleteButton函数中添加如下代码:
   CToolBarCtrl& ctrl=m_wndToolBar1.GetToolBarCtrl();
//DeleteButton(4)中的4表示要留下4个按钮不删除

   ASSERT(ctrl.DeleteButton(4));
CFrameWnd::ShowControlBar(&m_wndToolBar1,TRUE,TRUE);
  运行程序后,我们按ID_BUTTON实现了添加一个按钮,现在我们试试按钮这个新增的ID_BUTTONCOOL,结果是,如果现在你的工具栏上少于四个按钮,那么会报错,大于四个时,这个按钮前的一个按钮会被删除,直到工具栏上的按钮等于四才报错。所以我们要限制一下删除的个数,使它在工具栏上按钮少于或者等于4个时不执行删除操作,修改原代码如下:
   CToolBarCtrl& ctrl=m_wndToolBar1.GetToolBarCtrl();
//获得工具栏上按钮的个数
int bCount=ctrl.GetButtonCount();
//如果按钮数大于4个时执行删除操作
   if (bCount>4)
   {
   ASSERT(ctrl.DeleteButton(4));
CFrameWnd::ShowControlBar(&m_wndToolBar1,TRUE,TRUE);
}
通过上面的动态添加、删除工具栏按钮就可以实现Photoshop中的工具栏风格了。当然,你也可以增加一个删除循环一次删除多个按钮。
五、为工具栏按钮加入下拉菜单
  在工具栏的按钮样式中有一种是下拉菜单式的按钮,只要在新增一个按钮时设置其风格为TBSTYLE_DROPDOWN便可实现,把上面OnAddButton函数中新建按钮的代码修改如下:
void CMainFrame::OnAddButton(void)
{
CToolBarCtrl& ctrl=m_wndToolBar1.GetToolBarCtrl();
//设置新增按钮的样式为下拉菜单式按钮
ctrl.SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
int bmindex=ctrl.AddBitmap(1,IDB_BITMAP1);
TBBUTTON   bt;
ZeroMemory(&bt,sizeof(TBBUTTON));
bt.fsState|=TBSTATE_ENABLED;
//载入样式
bt.fsStyle|=TBSTYLE_DROPDOWN;
bt.iBitmap=bmindex;
bt.idCommand=ID_BUTTONCOOL;
bt.iString=0;
ASSERT(ctrl.AddButtons(1,&bt));
RecalcLayout();
CFrameWnd::ShowControlBar(&m_wndToolBar1,TRUE,TRUE);
}
  现在我们要实现在按下这个新增按钮时弹出一个菜单,并且使其刚好显示在按钮的附近,那么我们在刚才的OnDeleteButton函数中加入如下代码:
//定义一个坐标数据类
CPoint pot;
//获得当前鼠标的位置   
   GetCursorPos(&pot);
//定义一个菜单数据类
    CMenu menuPopup;

if(menuPopup.CreatePopupMenu())
{
//向菜单 menuPopup 中添加菜单项
menuPopup.AppendMenu(MF_STRING,ID_COIN_ADD,_T("增加硬币 Ctrl+A"));
menuPopup.AppendMenu(MF_STRING,ID_COIN_SUB,_T("减少硬币 Ctrl+B"));
//在当前鼠标位置显示弹出式菜单,并对用户选择的菜单项作出反应
menuPopup.TrackPopupMenu(TPM_LEFTALIGN,pot.x,pot.y,this);
}
  暂时不要急着执行此程序,因为你很可能忘记要先在资源文件中定义菜单项的名称,在resource.h里打上两句:
#define ID_COIN_ADD                    32776
#define ID_COIN_SUB                    32777
  执行后动态添加一个按钮,然后就可以看见点击按钮后在当前点击按钮的位置显示出菜单了,但现在你会发现点击按钮旁边的箭头时没任何反应,这是怎么回事呢?