您的位置:首页 > 运维架构

(转)工具条研究手记(6)- 在工具条上面创建控件并响应

2011-03-08 16:29 387 查看
/*****************************************************************/
/*       工具条研究手记(6)- 在工具条上面创建控件并响应                           */
/*****************************************************************/

一、工具条上面创建组合框,并响应组合框的选择消息。

通常由两种方法在工具条上面添加组合框对象,一种方法是从CToolBar派生一个工具条类,然后嵌入一个组合框,生成工具条以后,创建这个组合框,替换工具条上面的一个分割栏。另一种方法是在工具条的父窗口中(通常是框架窗口)嵌入一个组合框,创建的方法相同。下面分别举例:

1、派生工具条类

第一步:用ClassWizard从CToolBar派生一个CMyToolBar工具条类,然后添加一个public 组合框对象:

class CMyToolBar : public CToolBar
{
public:
 CMyToolBar();
 virtual ~CMyToolBar();
public:
 CComboBox    m_Combo;

 DECLARE_MESSAGE_MAP()
};
不用添加任何函数。

第二步:把框架窗口类中的工具条类,改成派生类对象:

#include "mytoolbar.h"

class CMainFrame : public CFrameWnd
{
......
protected:  // control bar embedded members
 CStatusBar   m_wndStatusBar;
 CMyToolBar   m_wndToolBar;
......
};

第三步:在工具条上面添加一个按钮,设置一个ID,比如 ID_MYCOMBOBOX,准备在这个按钮的位置创建组合框,而且组合框对象的ID就用这个ID。

第四步:正常创建工具条以后,创建该内嵌组合框:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
 if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
  return -1;

//创建这个工具条 
 if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
  | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
  !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
 {
  TRACE0("Failed to create toolbar/n");
  return -1;     // fail to create
 }

 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
 EnableDocking(CBRS_ALIGN_ANY);
 DockControlBar(&m_wndToolBar);

//下面的代码开始生成工具条按钮上面的组合框。注意该组合框要代替的按钮的id是ID_MYCOMBOBOX
//-------------------------------------------------------------------------
    int index = 0;
    RECT rect;

    //找到指定的工具项
    while(m_wndToolBar.GetItemID(index)!=ID_MYCOMBOBOX) index++;
    //或者使用 ?int index = m_wndToolBar.CommandToIndex(ID_MYCOMBOBOX);

    //设置指定工具项的宽度并获取新的区域? 80是宽度
    m_wndToolBar.SetButtonInfo(index, ID_MYCOMBOBOX, TBBS_SEPARATOR, 80);
    //取得该工具条项的矩形区域
    m_wndToolBar.GetItemRect(index, &rect);

   //注意适当调整位置,更美观
    rect.top+=2;
   rect.bottom += 200;

   // 创建组合框并显示
   if (!m_wndToolBar.m_Combo.Create(WS_CHILD|WS_VISIBLE | CBS_AUTOHSCROLL | 
                                                             CBS_DROPDOWNLIST | CBS_HASSTRINGS ,
                                                            rect, &m_wndToolBar, ID_MYCOMBOBOX))
                                  //注意父窗口使用该工具条,ID使用  ~~~~~~~~~~~~
     {
       TRACE0("Failed to create combo-box/n");
         return FALSE;
     }
       m_wndToolBar.m_Combo.ShowWindow(SW_SHOW);
    
    //添加组合框的内容
    m_wndToolBar.m_Combo.AddString("25%");
    m_wndToolBar.m_Combo.AddString("50%");
    m_wndToolBar.m_Combo.AddString("75%");
    m_wndToolBar.m_Combo.AddString("100%");
    m_wndToolBar.m_Combo.SetCurSel(3);
//-------------------------------------------------------------------------
    ......//其它代码

    return 0;
}

第五步:添加组合框响应的代码:

响应组合框和对话框中响应一个组合框相同,可以参考对话框中的代码,如下:

(1)mainfrm.h头文件中添加一个响应函数,响应组合框的选择变化消息

 void OnSelChangeMyCombo();

(2)mainfrm.cpp文件消息映射表中添加

 ON_CBN_SELCHANGE(ID_MYCOMBOBOX,OnSelChangeMyCombo)
或者 ON_CONTROL(CBN_SELCHANGE,ID_MYCOMBOBOX,OnSelChangeMyCombo)
或者 ON_CBN_SELENDOK(ID_MYCOMBOBOX,OnSelChangeMyCombo)

(3)添加响应函数:

 void CMainFrame::OnSelchangeCombo1() 
 {
  CString str;
  m_wndToolBar.m_Combo.GetLBText(m_Combo.GetCurSel(),str);
  MessageBox(str);
 }

其它组合框消息也可以响应,这些消息的映射代码是:
// Combo Box Notification Codes
#define ON_CBN_ERRSPACE(id, memberFxn) /
 ON_CONTROL(CBN_ERRSPACE, id, memberFxn)
#define ON_CBN_SELCHANGE(id, memberFxn) /
 ON_CONTROL(CBN_SELCHANGE, id, memberFxn)
#define ON_CBN_DBLCLK(id, memberFxn) /
 ON_CONTROL(CBN_DBLCLK, id, memberFxn)
#define ON_CBN_SETFOCUS(id, memberFxn) /
 ON_CONTROL(CBN_SETFOCUS, id, memberFxn)
#define ON_CBN_KILLFOCUS(id, memberFxn) /
 ON_CONTROL(CBN_KILLFOCUS, id, memberFxn)
#define ON_CBN_EDITCHANGE(id, memberFxn) /
 ON_CONTROL(CBN_EDITCHANGE, id, memberFxn)
#define ON_CBN_EDITUPDATE(id, memberFxn) /
 ON_CONTROL(CBN_EDITUPDATE, id, memberFxn)
#define ON_CBN_DROPDOWN(id, memberFxn) /
 ON_CONTROL(CBN_DROPDOWN, id, memberFxn)
#define ON_CBN_CLOSEUP(id, memberFxn)  /
 ON_CONTROL(CBN_CLOSEUP, id, memberFxn)
#define ON_CBN_SELENDOK(id, memberFxn)  /
 ON_CONTROL(CBN_SELENDOK, id, memberFxn)
#define ON_CBN_SELENDCANCEL(id, memberFxn)  /
 ON_CONTROL(CBN_SELENDCANCEL, id, memberFxn)

2、不派生工具条类,直接把组合框放在框架窗口类中:

省略第一步。
第二步:在框件窗口类中添加组合框对象:
class CMainFrame : public CFrameWnd
{
......
protected:  // control bar embedded members
 CStatusBar  m_wndStatusBar;
 CToolBar    m_wndToolBar; ?//正常的工具条对象
 CComboBox     m_Combo;??//添加组合框对象
......
};
第三、四、五步和上面相同,注意不用m_wndToolBar.m_Combo,直接使用m_Combo。

3、使用组合框时,应注意的几个问题:

(1)如果工具条没有TBSTYLE_FLAT属性,则不显示分割条,组合框可以正常显示,如果工具条用CreateEx创建,或者给出TBSTYLE_FLAT,则分割条会显示出来,缺省的工具条高度和组合框的高度差不多,正常情况下看不到组合框下面的分割条。但是如果给工具条按钮设置了文字,则工具条的高度加大,就看到组合框的中间(因为分割条是画在它的rect的中央)上下都出现部分分割条,非常不好看。目前我没有找到解决办法。
(2)如果工具条是浮动的,也就是说加入了如下的代码:
 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
 EnableDocking(CBRS_ALIGN_ANY);
 DockControlBar(&m_wndToolBar);
并且添加了文字:
 // 添加按钮文字
 for(int i=0;i 〈m_wndToolBar.GetToolBarCtrl().GetButtonCount();i++){
  UINT uButtonID = m_wndToolBar.GetItemID(i);
  CString str;
  if(str.LoadString(uButtonID))
  {
   int p = str.Find("/n");
   if(p)
   {
   CString strText = str.Right(str.GetLength() - p - 1);
   m_wndToolBar.SetButtonText( i, strText);
   }
  }
}

则工具条的宽度是按照按钮的尺寸和数量计算的,由于组合框占用了比较宽的位置,会造成整个工具条宽度不够,导致后面的按钮被裁剪掉而看不见。解决的方法是加大按钮的尺寸:
 m_wndToolBar.SetSizes(CSize(60,40),CSize(16,16));
                                            ~~~~ 主要是这个按钮的宽度尺寸

二、工具条上面创建一个滑动条(CSliderCtrl),并响应它。

在这个例子中,我们在工具条上面创建一个滑动条,然后根据它的滑动位置,调整一个图像在视图中的显示比例。

第一步:用ClassWizard创建一个名称为tbSlider的单文档工程,全部使用缺省设置。

第二步:打开资源编辑器,找到工具条,然后添加一个按钮, ID是 IDC_SLIDER。

第三步:打开MainFrm.h,添加一个滑动条对象:

class CMainFrame : public CFrameWnd
{

protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)

// Attributes
public:
CSliderCtrl m_Slider;
.....

第四步:打开MainFrm.cpp 添加创建代码:

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
// 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);
//-------------------------------------------------------------------
// 下面是添加的代码

    int index = m_wndToolBar.CommandToIndex(IDC_SLIDER);

    m_wndToolBar.SetButtonInfo(index, IDC_SLIDER, TBBS_SEPARATOR, 80);

    CRect rect;
    m_wndToolBar.GetItemRect(index, &rect);

    // 创建滑动条并显示
    if (!m_Slider.Create(WS_CHILD|WS_VISIBLE | TBS_HORZ | TBS_AUTOTICKS |TBS_BOTTOM ,
          rect, &m_wndToolBar, IDC_SLIDER))
   {
       TRACE0("Failed to create slider ctrl/n");
     return FALSE;
   }
   //设置滑动的范围
   m_Slider.SetRange(0,100);
   m_Slider.SetPos(20);
   m_Slider.ShowWindow(SW_SHOW);
//-------------------------------------------------------------------
    return 0;
}

第五步:我们这次在视类响应这个滑动条的消息,打开视类的头文件添加响应函数和绘图参数:

class CTbSliderView : public CView
{
......
// Operations
public:
 CBitmap m_bmp; //要绘制的位图
 double  r; //绘制的比例
 void OnReleasedcaptureSlider(); //响应函数
......

第六步:给视类重载OnInitialUpdate函数。然后打开视类CPP文件,添加如下的代码:

......
#include "mainfrm.h" //包含框架类的头文件
......
BEGIN_MESSAGE_MAP(CTbSliderView, CView)
......
 ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER, OnReleasedcaptureSlider)
END_MESSAGE_MAP()

//当用鼠标调整滑动条的位置,释放鼠标以后,滑动条会发送这个NM_RELEASEDCAPTURE消息

/////////////////////////////////////////////////////////////////////////////
// 响应函数
void CTbSliderView::OnReleasedcaptureSlider()
{
 CMainFrame * pMain = (CMainFrame*)AfxGetMainWnd();
 int pos = pMain->m_Slider.GetPos();
 int min,max;
 pMain->m_Slider.GetRange(min,max);
 //计算缩放比例,最小缩放比例25%,最大比例4
 r = (double)((pos - min)*3.75/(max-min) + 0.25);
 //刷新窗口,重新绘制图像
 Invalidate();
}

void CTbSliderView::OnInitialUpdate() 
{
 CView::OnInitialUpdate();
  // 加载工程目录中的一个位图,别忘了找一个大小合适的位图放在工程的目录里面
 HBITMAP hbmp = 0;
 hbmp = (HBITMAP)LoadImage(NULL,"02.bmp",IMAGE_BITMAP,0,0,
    LR_DEFAULTSIZE | LR_LOADFROMFILE | LR_CREATEDIBSECTION);

 if(hbmp) this->m_bmp.Attach(hbmp);
 
}

CTbSliderView::CTbSliderView()
{
 // 构造函数里面把比例系数缺省设置成1
 r = 0.25;
}

CTbSliderView::~CTbSliderView()
{
}

BOOL CTbSliderView::PreCreateWindow(CREATESTRUCT& cs)
{
 // TODO: Modify the Window class or styles here by modifying
 //  the CREATESTRUCT cs

 return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CTbSliderView drawing

void CTbSliderView::OnDraw(CDC* pDC)
{
 CTbSliderDoc* pDoc = GetDocument();
 ASSERT_VALID(pDoc);
 // TODO: add draw code for native data here
 if(m_bmp.m_hObject!=NULL)
 {
  //取得客户区尺寸
  CRect clientRect;
  GetClientRect(&clientRect);
  //取得位图的尺寸,按照比例缩放
  BITMAP bm;
  m_bmp.GetBitmap(&bm);
  int w = bm.bmWidth;
  int h = bm.bmHeight;

  //计算缩放以后图像的大小
  int rw = (int)((double)w * r);
  int rh = (int)((double)h * r);

  //计算绘制图像的起始位置,图像居中显示
  int sx = (clientRect.Width() - rw)/2;
  int sy = (clientRect.Height() - rh)/2;
  //调整,看是否位于客户区内
  if(sx < 0) sx = 0;
  if(sy < 0) sy = 0;

  //绘制图像
  CDC memDC;
  memDC.CreateCompatibleDC(pDC);
  CBitmap *pOldBitmap = memDC.SelectObject(&m_bmp);
  pDC->StretchBlt(sx,sy,rw,rh,&memDC,0,0,w,h,SRCCOPY);
  memDC.SelectObject(pOldBitmap);
 }
}

一切ok了,编译运行一下看看效果把,如果那里没有讲到,请多指正。

三、工具条上面创建一个编辑框和一个Spin控件,并且可以用Spin调整编辑框中的数字。

第一步:用ClassWizard创建一个名称为TbEditSpin的单文档工程,全部使用缺省设置。

第二步:打开资源编辑器,找到工具条,然后添加两个相邻的按钮, ID分别是 IDC_TOOLBAREDIT和
              IDC_TOOLBARSPIN 。

第三步:打开mainfrm.h,添加控件
public:
 CEdit m_ToolBarEdit;
 CSpinButtonCtrl m_ToolBarSpin;
第四步:打开mainfrm.cpp 创建控件

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
 EnableDocking(CBRS_ALIGN_ANY);
 DockControlBar(&m_wndToolBar);
//----------------------------------------------------------
// 下面是添加的代码

    CRect rect;

 int index = m_wndToolBar.CommandToIndex(IDC_TOOLBAREDIT);

   //设置指定编辑框的宽度 80
   m_wndToolBar.SetButtonInfo(index, IDC_TOOLBAREDIT, TBBS_SEPARATOR, 80);
   m_wndToolBar.GetItemRect(index, &rect);

   // 创建编辑框并显示
   if (!m_ToolBarEdit.Create(WS_CHILD|WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL ,
                        rect, &m_wndToolBar, IDC_TOOLBAREDIT))
   {
      TRACE0("Failed to create Edit-box/n");
      return FALSE;
   }
   m_ToolBarEdit.ShowWindow(SW_SHOW);

 //--------------------
 //创建SPIN控件
 index = m_wndToolBar.CommandToIndex(IDC_TOOLBARSPIN);

   //设置宽度 10
   m_wndToolBar.SetButtonInfo(index, IDC_TOOLBARSPIN, TBBS_SEPARATOR, 10);
   m_wndToolBar.GetItemRect(index, &rect);

   if (!m_ToolBarSpin.Create(WS_CHILD|WS_VISIBLE |UDS_ARROWKEYS | UDS_SETBUDDYINT,// | UDS_ALIGNRIGHT,
                                      rect, &m_wndToolBar, IDC_TOOLBARSPIN))
   {
      TRACE0("Failed to create Spin/n");
       return FALSE;
   }
    m_ToolBarSpin.ShowWindow(SW_SHOW);

 m_ToolBarSpin.SetRange(1,100);
 m_ToolBarSpin.SetPos(50);
 m_ToolBarSpin.SetBuddy(&m_ToolBarEdit);
 m_ToolBarEdit.SetWindowText("50");
//-------------------------------------------------------------------------
 return 0;
}

第五步:在视类里面响应控件,可以响应编辑框文字的变化,也可以响应Spin控件,这里给出后者:

//头文件
class CTbEditSpinView : public CView
{
......
// Operations
public:
 CString strSpin; //显示信息的字符串
 //响应函数,因为是通过ON_NOTIFY响应,所以带有两个参数
 void OnChangeToolbarSpin(NMHDR* pNMHDR, LRESULT* pResult);

//CPP文件
#include "stdafx.h"
#include "tbEditSpin.h"
#include "tbEditSpinDoc.h"
#include "tbEditSpinView.h"
#include "mainfrm.h" //加上这个
......

BEGIN_MESSAGE_MAP(CTbEditSpinView, CView)
......
 ON_NOTIFY(UDN_DELTAPOS, IDC_TOOLBARSPIN, OnChangeToolbarSpin)
 // ON_EN_CHANGE(IDC_TOOLBAREDIT, OnChangeToolbarEdit) //响应编辑框

END_MESSAGE_MAP()

void CTbEditSpinView::OnChangeToolbarSpin(NMHDR* pNMHDR, LRESULT* pResult) 
{
 NMUPDOWN* pNMUpDown = (NMUPDOWN*)pNMHDR;

 int curPos = pNMUpDown->iPos;
 int direct = pNMUpDown->iDelta;
 CString strPos = (direct>0)?("你按了上箭头"):("你按了下箭头");
 strSpin.Format("%s, 当前位置是:%d",strPos,curPos);
 Invalidate();

 *pResult = 0;
}

// 显示信息
void CTbEditSpinView::OnDraw(CDC* pDC)
{
 CRect rect;
 GetClientRect(&rect);
 pDC->DrawText(strSpin,&rect,DT_CENTER | DT_VCENTER |DT_SINGLELINE);
}

CTbEditSpinView::CTbEditSpinView()
{
 strSpin = _T("");
}

//-----------------------------------------------------------------------

4、总结。

上面一共给出三个例子,大同小异,基本上给出了工具条上面添加控件并且响应控件的做法。如果以后发现更好的例子和这个做法不同的,我会继续贴出。

工具条上面使用控件还可以通过CDialogBar来做,这个话题将放在另外一篇文章里面谈。

//--------------------------------------
// End
// iwaswzq 2004/11/25

 

转自: http://blog.vckbase.com/iwaswzq/archive/2007/08/01/1766.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息