演练VC中的COMMON一族(转贴)之三

6.3.7 工具条的消息映射技巧
    如果工具条上的按钮都存在对应的菜单命令,那么可以直接利用类向导ClassWizard 进行命令消息的映射,否则必须通过手工的方法来进行命令按钮的消息映射。由于同一工具栏的命令按钮都存在相类似的功能,所以只要注意将同一工具条中的命令按钮ID值设置成连续值,就可以利用范围命令处理机制统一对所有按钮命令进行管理,即所有命令按钮的消息可以在同一命令消息处理函数和更新命令消息处理函数中进行管理,这样不但结构紧凑而且维护特别方便。鉴于类向导ClassWizard 不支持范围命令处理功能,所以其消息映射机制必须通过手工方式来完成。按钮命令消息既可以在框架窗口中映射,也可以在文档和视图中完成映射,由于文档对象通常用来管理程序中的数据部分,并且在多文档应用程序(MDI) 中,一个文档可能有多个视图与之关联,因此把工具栏中的命令按钮消息映射在文档中比较合适些。其实现步骤如下:
    (1)在文档实现文件CToolDoc.h中增加函数定义和数据成员:
    class CCTOOLDoc : public CDocument
    {......//其它代码
    protected:
    UINT iPosition; file://命令按钮消息位置
    ......//其它代码
    protected:
        file://{{AFX_MSG(CCTOOLDoc)
        afx_msg void OnTool(UINT nID);//命令消息映射
        afx_msg void OnUpdateTool(CCmdUI* pCmdUI);//更新消息映射
        file://}}AFX_MSG
        DECLARE_MESSAGE_MAP()
    ......//其它代码
    }
    (2)在文档实现文件CToolDoc.cpp中进行消息映射
    BEGIN_MESSAGE_MAP(CCTOOLDoc,CDocument)
        file://{{AFX_MSG_MAP(CCTOOLDoc)
        ON_COMMAND_RANGE(ID_BUTTON_LINE,
          ID_BUTTON_SORT,OnTool);
        ON_UPDATE_COMMAND_UI_RANGE(ID_BUTTON_LINE,
          ID_BUTTON_SORT,OnUpdateTool);
        file://}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    函数中的参数ID_BUTTONLINE和ID_BUTTONSORT分别为工具栏中第一个按钮和最后一个按钮的消息,如果要增加或减少了按钮数,则必须使其ID值保持连续,并且需要修改函数中的最后一个消息值。对应函数的代码如下:
    void CtoolDoc::OnTool(UINT nID)
    {    file://按钮消息处理函数
         iPosition=nID-ID_BUTTON_LINE;
         switch(iPosition){
           case 1:
             ......//调用按钮一的处理功能
           case 2:
             ......//调用按钮二的处理功能
           ......
           case n:
             ......//调用按钮N的处理功能
           break;
         }
    }
    void CToolDoc::OnUpdateTool(CCmdUI* pCmdUI)
    {    file://更新按钮函数
         pCmdUI->SetCheck(iPosition==(pCmdUI->m_nID
           -ID_BUTTON_LINE));
    }
    由于命令按钮比较多,其处理功能代码部分这里省略。
6.3.8 驾驭工具条按钮的状态显示更新
    (1)互斥按钮的状态更新
    很多应用程序中都存在相互排斥的工具条按钮,如开始和停止按钮,初始状态时停止按钮被禁止,当应用程序进行数据通讯、查找和打印等功能时,停止按钮有效而开始按钮禁止,当命令结束或按停止按钮后,开始按钮有效而停止按钮被禁止。这就是工具条中按钮的显示状态更新问题。
    与菜单栏一样,工具条的构造、析构过程及其窗口的创建都是由应用程序的主框架窗口来管理的。当用户点击菜单条的菜单项时,Windows 就会向应用程序发送WM_INITMENUPOPUP消息,以便应用程序在菜单显示之前对菜单项进行添加或修改,当利用MFC 类库编程时只要针对某一具体的菜单项进行消息映射,加入相应的消息处理函数,MFC类库就会发送更新消息UPDATE_COMMAND_UI,使菜单在弹出时消息处理函数能够对菜单项进行禁止、变灰和其它处理。工具条的消息处理过程与菜单栏完全相同,它也存在工具条显示更新消息UPDATE_COMMAND_UI ,只不是由于工具条总是处于显示状态,所以对其消息处理函数的调用是在应用程序的空闲状态时进行处理的,这点与菜单栏有所不同,当应用程序命令按钮所要执行的功能占用大量的处理器资源时,如进行通讯处理或大量数据计算时,应用程序的主框架窗口就无暇进入空闲状态,于是工具条中的命令按钮函数就不能被及时调用,按钮的显示状态就不能被及时更新,这就为工具条按钮的显示状态及时更新带来一定的困难。
    基于文档的应用程序一般情况下都是在文档视中对工具条按钮进行处理,所以要实现按钮显示状态的及时更新,必须在命令按钮响应函数中利用CToolBarCtrl类的成员函数EnableButton()函数对按钮的显示状态进行必要的处理,其步骤如下:
    ①首先利用类向导ClassWizard 对CCTOOLView类进行开始按钮和停止按钮的COMMAND命令消息映射,增加对应消息的处理函数;
    ②在实现文件CTOOLView.h中增加成员变量:
    public:
        BOOL m_bContiune;//开始按钮标志
        BOOL m_bSet;//结束按钮标志
    ③在实现文件CTOOLView.cpp中增加代码完善按钮状态更新:
    ......//其它代码
    void DrawRectText(RECT &rc,CDC &dc);
    ......//其它代码
    void CCTOOLView::OnButtonStart()
    {   file://完善开始按钮函数功能
        CToolBar *pToolBar=(CToolBar *)//取得工具栏对象指针
          (GetParentFrame()->GetControlBar(IDR_DOCKTOOLBAR));
          file://取得工具条控制指针
        CToolBarCtrl *pToolBarCtrl=&(pToolBar->GetToolBarCtrl());
          file://控制工具条按钮状态
        pToolBarCtrl->EnableButton(ID_BUTTON_START,FALSE);
        pToolBarCtrl->EnableButton(ID_BUTTON_STOP,TRUE);
        CClientDC dc(this);//取得设备文本
        MSG msg;//定义消息
        RECT rc;
        GetClientRect(&rc);//以下画网格并显示
        m_bContinue=TRUE;
        m_bSet=FALSE;
        for(int ii=0;ii<2;ii++){
           if(m_bContinue==TRUE){
             ii=0;//状态改变退出
             DrawRectText(rc,dc);
             GetMessage(&msg,NULL,0,0);//检查消息
             TranslateMessage(&msg);//解释消息
             DispatchMessage(&msg);//分配消息
           }
        }
        ReleaseDC(&dc);
        m_bSet=TRUE;
    }
    void DrawRectText(RECT &rc,CDC &dc)
    {   file://显示文本函数
        int i,j,k,nDist=10;
        CPen pen,*pOldPen;
        pen.CreatePen(PS_SOLID,1,RGB(180,0,0));
        pOldPen=dc.SelectObject(&pen);//绘制背景网格
        j=rc.right/nDist+1;
        k=rc.bottom/nDist+1;
        for(i=0;i<j+k;i++){
          dc.MoveTo(i*nDist,0);
          dc.LineTo(0,i*nDist);
          if(i<j){
            dc.MoveTo(i*nDist,0);
            dc.LineTo(rc.right,(j-i)*nDist);
          } else {
            dc.MoveTo(0,(i-j)*nDist);
            dc.LineTo(rc.right,i*nDist);
          }
        }
        dc.SelectObject(pOldPen);
        DeleteObject(&pen);
        CFont font,*pOldFont;
        font.CreateFont(50,50,0,0,1000,//创建字体
          1,1,0,ANSI_CHARSET,
          OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
          DEFAULT_QUALITY,DEFAULT_PITCH,NULL);
        pOldFont=dc.SelectObject(&font);
        dc.TextOut(10,10,"BUTTON");
        dc.SelectObject(pOldFont);
        DeleteObject(&font);
    }
    void CCTOOLView::OnButtonStop()
    {   file://完善停止按钮函数
        m_bContinue=FALSE;
        CToolBar *pToolBar=(CToolBar *)//取得工具栏对象指针
          (GetParentFrame()->GetControlBar(IDR_DOCKTOOLBAR));
          file://取得工具条控制指针
        CToolBarCtrl *pToolBarCtrl=&(pToolBar->GetToolBarCtrl());
          file://控制工具条按钮状态
        pToolBarCtrl->EnableButton(ID_BUTTON_START,TRUE);
        pToolBarCtrl->EnableButton(ID_BUTTON_STOP,FALSE);
        for(int jj=0;jj<2;jj++){
          if(m_bSet==FALSE){
            jj=0;
            GetMessage(&msg1,NULL,0,0);//检查消息
            TranslateMessage(&msg1);//解释消息
            DispatchMessage(&msg1);//分配消息
          }
        }
    }
    在开始按钮函数中,当在屏幕上不断显示信息的同时必须利用消息处理函数检查消息队列,并解释和分配相应的消息,否则其它按钮就无法检查到应用程序的鼠标等消息,无法实现显示状态更新;在更新按钮显示状态前,必须先取得工具栏对象和相应的控制指针,然后才能实现对按钮状态的控制,并且要实现按钮状态的更新,其设置按钮的更新功能函数必须最后执行结束才能有效,即在停止按钮函数中必须判断标志并检测消息队列。
    ④在平面工具条派生类中的鼠标按下函数中增加代码,以实现鼠标按下开始和停止按钮后,保证按钮的正常按下和显示状态:
    void CTestToolBar::OnLButtonDown(UINT nFlags, CPoint point)
    {   file://完善鼠标按下函数
        ......//其它代码
        if(m_nIndex==ToolBarCtrl.CommandToIndex(ID_BUTTON_STOP)){
          ToolBarCtrl.SetState(ID_BUTTON_STOP,ToolBarCtrl.GetState(
            ID_BUTTON_STOP)&(~TBSTATE_ENABLED&~TBSTATE_PRESSED));
          ToolBarCtrl.SetState(ID_BUTTON_START,ToolBarCtrl.
            GetState(ID_BUTTON_START)|TBSTATE_ENABLED);
          ToolBarCtrl.Invalidate();
          AfxGetApp()->OnIdle(-1);
          m_nIndex=0xffff;
        }
        if(m_nIndex==ToolBarCtrl.CommandToIndex(ID_BUTTON_START)){
          ToolBarCtrl.SetState(ID_BUTTON_START,ToolBarCtrl.GetState(
            ID_BUTTON_START)&(~TBSTATE_ENABLED & ~TBSTATE_PRESSED));
          ToolBarCtrl.SetState(ID_BUTTON_STOP,ToolBarCtrl.GetState(
            ID_BUTTON_STOP)&TBSTATE_ENABLED);
          ToolBarCtrl.Invalidate();
          AfxGetApp()->OnIdle(-1);
          m_nIndex=0xffff;
        }
    }
    (2)按钮按下状态的切换更新
    另一种按钮状态的更新情况是按钮按下状态的切换更新,这在绘图工具条和屏幕字体效果工具条中最常见。其实现步骤如下:
    ①首先在MainFrm.cpp中手工增加消息范围映射函数
    ON_COMMAND_RANGE(ID_EDIT_TOGGLE,ID_EDIT_UNINDENT,OnButton)
    ON_UPDATE_COMMAND_UI_RANGE(ID_EDIT_TOGGLE,
      ID_EDIT_UNINDENT,OnUpdateButton)
    ②然后在MainFrm.h中消息映射的最后增加成员函数定义和记录按下按钮序号的成员控制变量
        int  m_bIndex;//按下按钮序号
        afx_msg void OnButton(UINT nID);
        afx_msg void OnUpdateButton(CCmdUI* pCmdUI);
    ③最后分别增加实现消息函数的功能代码
    void CMainFrame::OnUpdateButton(CCmdUI* pCmdUI)
    {   file://按钮按下检查状态设置函数
        pCmdUI->SetCheck((UINT)(ID_EDIT_TOGGLE+
          m_bIndex) == pCmdUI->m_nID);
    }
    void CMainFrame::OnButton(UINT nID)
    {   file://记录按下按钮的序号
        m_bIndex=(int)(nID-ID_EDIT_TOGGLE);
    }
    如果涉及到其它控制的变化,可在这两个函数中分别增加。
    (3)按钮的部分显示更新
    最后一种更新工具条按钮显示状态的情况是部分按钮显示,这需要利用SetButtons()和SetButtonInfo()函数有效处理。步骤如下:
    ①首先在菜单栏中增加控制菜单项;
    ②在应用程序实现文件CTool.h中增加如下消息定义和函数定义
    ......//其它代码
    #define WM_IDLEACTIVATE WM_USER+1
    ......//其它代码
    class CCtrlbarsApp : public CWinApp
    {
    public:
        ......//其它代码
        virtual BOOL OnIdle(LONG lCount);
        ......//其它代码
    };
    ③在应用程序实现文件CTool. cpp中增加如下代码和副本函数功能,这个函数在工具条按钮的各种显示状态更新中都非常有用,是一个非常重要的程序设计技巧。
    在初始化函数CCTOOLApp::InitInstance()最后增加代码:
    m_pMainWnd = pMainFrame;
    完善相应的功能函数:
    BOOL CCTOOLApp::OnIdle(LONG lCount)
    {   file://保持应用程序一个副本函数
        if(lCount == 0){
          ASSERT(m_pMainWnd != NULL);
          for(HWND hWnd=::GetWindow(m_pMainWnd->m_hWnd,
            GW_HWNDFIRST);hWnd!=NULL;hWnd=::GetNextWindow(
            hWnd,GW_HWNDNEXT)){//获取主程序子窗口
              if(::GetParent(hWnd)==m_pMainWnd->m_hWnd){
                if(GetActiveWindow()==hWnd&&(::GetCapture()==NULL))
                  m_pMainWnd->SetActiveWindow();//保持应用程序活动窗口
                SendMessage(hWnd,WM_IDLEUPDATECMDUI,(WPARAM)TRUE,0L);
              }//保持窗口的一个有效副本
          }
        }
        return CWinApp::OnIdle(lCount);
    }
    ④最后在菜单项处理函数中进行工具条按钮的重组处理,并在需要处理应用程序窗口副本的任何函数中增加副本处理函数。
    void CMainFrame::OnViewShort()
    {
        m_wndMainToolBar.SetButtons(NULL,7);//共计7个
        m_wndMainToolBar.SetButtonInfo(0,ID_BUTTON_LINE,TBBS_BUTTON,1);
        m_wndMainToolBar.SetButtonInfo(1,ID_BUTTON_CURSE,TBBS_BUTTON,5);
        ......
        m_wndMainToolBar.SetButtonInfo(6,ID_BUTTON_TEST,TBBS_BUTTON,7);
        m_wndToolBar.Invalidate();//更新工具条
        AfxGetApp()->OnIdle(-1);//窗口副本处理函数
    }
6.3.9 工具条中的通用控制使用
    在工具条中通常不都是按钮,如存在输入框、下拉组合框和检查盒按钮等。这就需要利用VC中提供的特殊类型的工具条类控制或通过派生新类的方法来实现。
    (1)在派生的新类中实现控制
    如果利用派生新类的方法,很容易就可以实现文本输入框等通用控制功能。其实现步骤如下:
    ①利用类向导ClassWizard 建立新类CEDITBAR并生成实现文件;
    ②利用资源编辑器建立工具条的位图文件;
    ③在新类实现文件EDITBAR.h中增加如下函数定义和成员变量:
    class CEDITBAR : public CToolBar
    {
    public:
        CEDITBAR();
        CSearchBox m_SearchBox;//文本查找控制
        BOOL Init(CWnd* pParentWnd,BOOL bToolTips);
        BOOL SetColor(BOOL bColor);
        BOOL SetHorizontal();
        BOOL SetVertical();
        ......//其它代码
        BOOL m_bVertical;
        file://virtual CSize CalcFixedLayout(BOOL bStretch,BOOL bHorz);
        virtual CSize CalcDynamicLayout(int nLength,DWORD dwMode);
        ......//其它代码
    }
    ④在新类实现文件EDITBAR.cpp中增加如下函数:
    ......//其它代码
    #define COMBOBOX_INDEX 5      file://定义组合框参数
    #define COMBOBOX_WIDTH 150
    #define COMBOBOX_HEIGHT 150
    #define COMBOBOX_BITMAP 4
    static UINT BASED_CODE EditButtons[] =
    {   file://要求与工具栏位图顺序对应
        ID_EDIT_TOGGLE,
        ID_EDIT_NEXT,
        ID_EDIT_PREV,
        ID_EDIT_CLEARALL,
          ID_SEPARATOR,
        ID_EDIT_FINDEDIT,
          ID_SEPARATOR,
        ID_EDIT_FINDINFILES,
          ID_SEPARATOR,
        ID_EDIT_INDENT,
        ID_EDIT_UNINDENT,
          ID_SEPARATOR,
        ID_WINDOW_NEW,
        ID_WINDOW_SPLIT,
        ID_WINDOW_CASCADE,
        ID_WINDOW_HORZ,
        ID_WINDOW_VERT,
    };
    ......//其它代码
    BOOL CEDITBAR::Init(CWnd* pParentWnd,BOOL bToolTips)
    {   file://初始化输入框函数
        m_bVertical=FALSE;
        DWORD dwStyle=WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_SIZE_DYNAMIC;
        if(bToolTips)dwStyle|=(CBRS_TOOLTIPS|CBRS_FLYBY);
        if(!Create(pParentWnd,dwStyle,IDB_CEDIT)) return FALSE;
        if(!LoadBitmap(IDB_CEDIT)) return FALSE;
        if(!SetButtons(EditButtons,sizeof(EditButtons)
          /sizeof(UINT)))return FALSE;
        CRect rect(-COMBOBOX_WIDTH,-COMBOBOX_HEIGHT,0,0);
        // 非常重要:其一是可以从控制接收信息,如动态提示等
        if(!m_SearchBox.Create(WS_CHILD|CBS_DROPDOWN|//建立文本查找
          CBS_AUTOHSCROLL|WS_VSCROLL|CBS_HASSTRINGS,rect,this,
          IDC_EDITBAR_SEARCHBOX)) return FALSE;
        HFONT hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
        if(hFont==NULL)hFont=(HFONT)GetStockObject(ANSI_VAR_FONT);
        m_SearchBox.SendMessage(WM_SETFONT,(WPARAM)hFont);
        if(!SetHorizontal())return FALSE;
        return TRUE;
    }
    BOOL CEDITBAR::SetHorizontal()
    {   file://设置按钮水平排列函数
        m_bVertical=FALSE;
        SetBarStyle(GetBarStyle()|CBRS_ALIGN_TOP);
        SetButtonInfo(COMBOBOX_INDEX,IDC_EDITBAR_SEARCHBOX,
          TBBS_SEPARATOR, COMBOBOX_WIDTH);
        if(m_SearchBox.m_hWnd!=NULL){
          CRect rect;
          GetItemRect(COMBOBOX_INDEX,rect);
          m_SearchBox.SetWindowPos(NULL,rect.left,
            rect.top,0,0,SWP_NOZORDER|SWP_NOACTIVATE|
            SWP_NOSIZE|SWP_NOCOPYBITS);
          m_SearchBox.ShowWindow(SW_SHOW);
        }
        return TRUE;
    }
    BOOL CEDITBAR::SetVertical()
    {   file://设置按钮垂直排列函数
        m_bVertical=TRUE;
        SetButtonInfo(COMBOBOX_INDEX,ID_EDIT_FIND,
          TBBS_BUTTON, COMBOBOX_BITMAP);
        if(m_SearchBox.m_hWnd != NULL)
          m_SearchBox.ShowWindow(SW_HIDE);
        return TRUE;
    }
    CSize CEDITBAR::CalcDynamicLayout(int nLength, DWORD dwMode)
    {   file://设置固定大小工具条函数
        if (dwMode&LM_COMMIT) {
           if (dwMode&LM_VERTDOCK)
              if(!m_bVertical) SetVertical();
           else if(m_bVertical) SetHorizontal();
           return CToolBar::CalcDynamicLayout(nLength,dwMode);
        } else {
           BOOL bOld=m_bVertical;
           BOOL bSwitch=(dwMode & LM_HORZ)?bOld:!bOld;
           if (bSwitch){
              if (bOld) SetHorizontal();
              else SetVertical();}
           CSize sizeResult=CToolBar::CalcDynamicLayout(nLength,dwMode);
           if (bSwitch){
              if (bOld) SetHorizontal();
              else SetVertical();}
           return sizeResult;
        }
    }
    /*
    CSize CEDITBAR::CalcFixedLayout(BOOL bStretch,BOOL bHorz)
    {   file://设置可变大小工具条函数
        if(!bHorz&&(m_dwStyle&CBRS_SIZE_DYNAMIC)&&
          !(m_dwStyle&CBRS_FLOATING)){
          CSize size;
          size=CControlBar::CalcFixedLayout(bStretch,bHorz);
          CRect rect;
          rect.SetRectEmpty();
          CalcInsideRect(rect, bHorz);
          size.cx=m_sizeVert.cx+(m_rectInsideVert.Width()-rect.Width());
          size.cy=m_sizeVert.cy+(m_rectInsideVert.Height()-rect.Height());
          return size;
        } else {
          if(m_bVertical) SetHorizontal();
          return CToolBar::CalcFixedLayout(bStretch,bHorz);
        }
    }
    */
    ⑤利用类向导ClassWizard建立新类CSearchBox并生成实现文件,同时为新类增加解释消息,即在新类实现文件SearchBox.h中增加如下函数定义:
     virtual BOOL PreTranslateMessage(MSG* pMsg);
    ⑥在其实现文件SearchBox.cpp文件中完善相应函数
    BOOL CSearchBox::PreTranslateMessage(MSG* pMsg)
    {   file://消息解释函数
        if((pMsg->message!=WM_KEYDOWN)||(pMsg->wParam!=VK_RETURN))
          return CComboBox::PreTranslateMessage(pMsg);
        // 在下拉列表中增加最后15次输入的数据
        if((pMsg->lParam&0x40000000)==0){//不重复
          CString strText;
          GetWindowText(strText);
          InsertString(0,strText);
          SetCurSel(0);
          if(GetCount()>15)
            DeleteString(GetCount()-1);
        }
        return TRUE;
    }
    ⑦在主程序实现文件MainFrm.h中增加工具条定义
    #include "EDITBAR.H"
    CEDITBAR m_wndEditBar;//带输入框工具条
    ⑧在主程序实现文件MainFrm.cpp中增加代码:
    file://在建立函数OnCreate中增加
    if (!m_wndEditBar.Init(this,m_bToolTips)){
       TRACE0("带编输入工具条建立失败/n");
       return -1;}
    ......
    DockControlBarLeftOf(&m_wndEditBar,
      &m_wndTestToolBar);//连接工具条
    此外,还可以为工具条增加按钮检查状态等控制功能,详见工具条按钮的显示状态更新。
    (2)利用工具条风格类实现控制
    利用工具条风格类同样可以实现下拉列表等控制功能,其具体步骤如下:
    ①为工具栏建立位图按钮并定义按钮对应的消息,同前;
    ②在实现文件MainFrm.h中增加工具栏控制和函数定义;
     CStyleBar m_wndStyleBar;
     BOOL      CreateStyleBar()
    ③在实现文件MainFrm.cpp中增加控制代码
    在建立函数OnCreate中增加建立函数
    if (!CreateStyleBar()) return -1;
    增加建立相应工具条函数的代码
    BOOL CMainFrame::CreateStyleBar()
    {   file://建立具有下拉列表控制的工具条函数
        const int nDropHeight = 100;
        if(!m_wndStyleBar.Create(this,WS_CHILD|WS_VISIBLE|
          CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY,IDW_STYLES)||
          !m_wndStyleBar.LoadBitmap(IDB_STYLES)||!m_wndStyleBar.
          SetButtons(styles,sizeof(styles)/sizeof(UINT))){
            TRACE0("特殊风格工具条建立失败/n");
            return FALSE;
        }
        // 建立组合框
        m_wndStyleBar.SetButtonInfo(0,IDW_COMBO,TBBS_SEPARATOR,100);
        // 设置组合框与按钮间距离
        m_wndStyleBar.SetButtonInfo(1,ID_SEPARATOR,TBBS_SEPARATOR,12);
        CRect rect;
        m_wndStyleBar.GetItemRect(0,&rect);
        rect.top=3;
        rect.bottom=rect.top+nDropHeight;
        if (!m_wndStyleBar.m_comboBox.Create(//建立组合框
           CBS_DROPDOWNLIST|WS_VISIBLE|WS_TABSTOP,
           rect, &m_wndStyleBar, IDW_COMBO)){
           TRACE0("组合框建立失败/n");
           return FALSE;
        }
        CString szStyle;//填充组合框
        if (szStyle.LoadString(IDS_LEFT))
           m_wndStyleBar.m_comboBox.AddString((LPCTSTR)szStyle);
        ......//同类的其它代码
        LOGFONT logFont;//为组合框建立字体
        memset(&logFont,0,sizeof(logFont));
        if(!::GetSystemMetrics(SM_DBCSENABLED)){
          logFont.lfHeight=-12;
          logFont.lfWeight=FW_BOLD;
          logFont.lfPitchAndFamily=VARIABLE_PITCH|FF_SWISS;
          CString strDefaultFont;
          strDefaultFont.LoadString(IDS_DEFAULT_FONT);
          lstrcpy(logFont.lfFaceName, strDefaultFont);
          if(!m_wndStyleBar.m_font.CreateFontIndirect(&logFont))
            TRACE0("组合框建立字体失败/n");
          else m_wndStyleBar.m_comboBox.SetFont(&m_wndStyleBar.m_font);
        } else {
          m_wndStyleBar.m_font.Attach(::GetStockObject(SYSTEM_FONT));
          m_wndStyleBar.m_comboBox.SetFont(&m_wndStyleBar.m_font);
        }
        return TRUE;
    }
    同样,也可以为这个特殊风格的工具条增加其它控制功能。
    (3)利用对话框类建立多功能工具条
    利用对话框工具条类可以建立功能更加强大的工具条,在对话框中实现的功能都可以增加到工具条中去。工具步骤如下:
    ①利用对话框资源增加一个对话框IDD_DLGTOOLBAR,并设计好对话框中的所有功能及功能对应的ID标识;
    ②在实现文件MainFrm.h中增加对话框工具条类控制和成员变量
    CDialogBar   m_wndDlgBar; file://对话框工具条控制
    BOOL         m_bDialogTop;//顶部标志
    ③在实现文件MainFrm.cpp中增加控制代码
    在建立函数OnCreate函数的状态条建立函数后增加:
    UINT nID, nStyle;
    int cxWidth;
    m_wndStatusBar.GetPaneInfo(0,nID,nStyle,cxWidth);
    m_wndStatusBar.SetPaneInfo(0,nID,SBPS_STRETCH|SBPS_NORMAL,cxWidth);
    if(!m_wndDlgBar.Create(this,IDD_TOOLBARCTRL,
      CBRS_LEFT|CBRS_TOOLTIPS|CBRS_FLYBY,IDD_TOOLBARCTRL)){
      TRACE0("对话框工具条建立失败/n");
      return -1;
    }
    一定要注意EnableDocking(CBRS_ALIGN_ANY)函数在所有建立函数的前面,并且对话框工具条在状态条建立函数的后面。
    ④为对话框资源中的所有控制消息手工增加映射,并完善相应的映射函数,可以是工具条的显示与隐藏等功能。示例函数如下:
    BOOL CMainFrame::OnDocktool(UINT nID)
    {   file://控制工具条的显示与隐藏函数
        BOOL bVisible = ((m_wndDockToolBar.GetStyle() & WS_VISIBLE) != 0);
        ShowControlBar(&m_wndDockToolBar, !bVisible, FALSE);
        RecalcLayout();
        return TRUE;
    }
    void CMainFrame::OnUpdateDocktool(CCmdUI* pCmdUI)
    {   file://工具条检查状态更新
        BOOL bVisible = ((m_wndDockToolBar.GetStyle() & WS_VISIBLE) != 0);
        pCmdUI->SetCheck(bVisible);
    }
    ⑤在菜单中增加顶部控制菜单项,建立消息函数后按照工具条的停靠位置中的方法为其完善相应的顶部控制功能函数。
6.3.10 工具条的显示和隐藏
6.3.10.1 单一工具条的显示与隐藏
    在大型应用程序中可能存在很多工具条,而用户实际使用时可能只需要其中的一部分,这就需要控制工具条的显示隐藏。对于单个工具条,其菜单项的一般控制方法为:
    首先打开菜单编辑器,在查看菜单栏中增加工具条对应的子菜单项,如为TestToolBar 工具条增加的子菜单项的“测试”的ID为ID_BOTTON_TEST,其Caption 为“测试工具条”,依次增加其它工具条的控制子菜单项。利用类向导ClassWizard 为主框架窗口类CMainFrame增加各子菜单项的ONCOMMAND和ON_UPDATE_COMMAND_UI 消息映射功能函数,并完善对应的功能函数:
    void CMainFrame::OnButtonTest()
    {    file://菜单命令消息函数
         BOOL bVisible=((m_wndTestToolBar.GetStyle()&
              WS_VISIBLE)!=0);//取得工具条状态
         ShowControlBar(&m_wndTestToolBar,!bVisible,FALSE);
         RecalcLayout();//更新工具条
    }
    void CMainFrame::OnUpdateButtonTest(CCmdUI* pCmdUI)
    {    file://菜单更新函数
         BOOL bVisible=((m_wndTestToolBar.GetStyle()&
              WS_VISIBLE)!=0);//取得工具条状态
         pCmdUI->SetCheck(bVisible);//设置检查标志
    }
6.3.10.2 特殊工具条的显示与隐藏
    当存在利用CStyleBar 类等建立的具有特殊控制功能的工具条时,工具条的显示与消隐必须利用下面的函数:
    BOOL CMainFrame::OnEdittool(UINT nID)
    {   file://具有下拉组合框功能工具条显示与消隐函数
        CWnd* pBar;//工具条窗口指针
        if ((pBar=GetDlgItem(nID))==NULL)//取得鼠标点击项
           return FALSE;//控制工具条窗口风格
        pBar->ShowWindow((pBar->GetStyle()&WS_VISIBLE)==0);
        RecalcLayout();//重新显示窗口
        return TRUE;
    }
    void CMainFrame::OnUpdateEdittool(CCmdUI* pCmdUI)
    {   file://具有下拉组合框功能工具条状态更新
        CWnd* pBar;//工具条窗口指针
        if((pBar=GetDlgItem(pCmdUI->m_nID))==NULL){
          pCmdUI->ContinueRouting();//继续判断
          return;
        } file://设置检查状态
        pCmdUI->SetCheck((pBar->GetStyle()&WS_VISIBLE)!=0);
    }
6.3.10.3 多工具条的显示与隐藏
    如果存在很多工具条,使用菜单控制的方法并不方便,最好采用对话框设置的方法,如笔者在程序中通过对话框来控制工具条的显示与消隐、按钮排列数和动态提示功能的取舍。其步骤如下:
    ①首先打开资源列表中的对话框资源,利用"Insert->Resource->Dialog"插入对话框IDD_TOOLBAR,在对话框中建立四个工具条复选框按钮、四个排列数值的单选按钮和两个动态提示功能的单选按钮(请有关图形),并为各按钮设置ID标识和按钮名称,注意选中每组按钮中首按钮的Group属性;
    ②通过双击增加的对话框标题栏为对话框建立新类CToolDlg和两个实现文件ToolDlg.h和ToolDlg.cpp;
    ③打开对话框实现文件ToolDlg.h,增加如下成员控制变量:
    class CToolDlg : public CDialog
    {   ......//其它代码
        file://{{AFX_DATA(CToolDlg)
        enum { IDD = IDD_TOOLBAR };
        BOOL    m_bMainTool;//各工具条控制变量
        BOOL    m_bTestTool;
        BOOL    m_bDockTool;
        BOOL    m_bDockNext;
        int     m_nToolTips;//动态提示控制变量
        int     m_nColumns; file://按钮排列数控制变量
        ......//其它代码
    }
    ④在实现文件ToolDlg.cpp中增加如下控制代码:
    CToolDlg::CToolDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CToolDlg::IDD, pParent)
    {   file://完善成员变量初始化
        file://{{AFX_DATA_INIT(CToolDlg)
        m_bMainTool = FALSE;
        m_bTestTool = FALSE;
        m_bDockTool = FALSE;
        m_bDockNext = FALSE;
        m_nToolTips = -1;
        m_nColumns = -1;
        file://}}AFX_DATA_INIT
    }
    void CToolDlg::DoDataExchange(CDataExchange* pDX)
    {   file://完善对话框按钮状态初始化
        CDialog::DoDataExchange(pDX);
        file://{{AFX_DATA_MAP(CToolDlg)
        DDX_Check(pDX,IDC_MAINTOOL,m_bMainTool);
        DDX_Check(pDX,IDC_TESTTOOL,m_bTestTool);
        DDX_Check(pDX,IDC_DOCKTOOL,m_bDockTool);
        DDX_Check(pDX,IDC_DOCKNEXT,m_bDockNext);
        DDX_Radio(pDX,IDC_SHOW,m_nToolTips);
        DDX_Radio(pDX,IDC_TWO,m_nColumns);
        file://}}AFX_DATA_MAP
    }
    ⑤在主程序实现文件MainFrm.cpp 中增加ToolDlg.h 包含文件,并完善相应菜单选项功能。如笔者程序中为完善“测试”选项的功能,其控制代码如下:
    void CMainFrame::OnButtonTest()
    {   file://完善相应菜单选项
        CToolDlg ToolDlg;//调出对话框
        UINT nColumns = m_wndDockToolBar.GetColumns();
        nColumns -= 2;//取得按钮排列数
        file://取得工具栏的可视风格
        ToolDlg.m_bMainTool=((m_wndMainToolBar.
          GetStyle()&WS_VISIBLE)!=0);
        ToolDlg.m_bTestTool=((m_wndTestToolBar.
          GetStyle()&WS_VISIBLE)!=0);
        ToolDlg.m_bDockTool=((m_wndDockToolBar.
          GetStyle()&WS_VISIBLE)!=0);
        ToolDlg.m_bDockNext=((m_wndDockNextBar.
          GetStyle()&WS_VISIBLE)!=0);
        ToolDlg.m_nColumns=nColumns;
        ToolDlg.m_nToolTips=(m_bToolTips)?0:1;
        if (IDOK==ToolDlg.DoModal())
        {  file://控制工具条的显示与消隐
           ShowControlBar(&m_wndMainToolBar,
             ToolDlg.m_bMainTool,FALSE);
           ......//其它工具条控制代码,基本相同
           m_bToolTips=(ToolDlg.m_nToolTips==0);
           if (m_bToolTips){//控制动态提示功能
              m_wndMainToolBar.SetBarStyle(m_wndMainToolBar.
                GetBarStyle()|CBRS_TOOLTIPS|CBRS_FLYBY);
              ......//其它工具条控制代码,基本相同
           } else {
              m_wndMainToolBar.SetBarStyle(m_wndMainToolBar.
                GetBarStyle()&(CBRS_TOOLTIPS|CBRS_FLYBY));
              ......//其它工具条控制代码,基本相同
           }
           nColumns=ToolDlg.m_nColumns+2;//控制工具条按钮列数
           m_wndDockToolBar.SetColumns(nColumns);
           m_wndDockNextBar.SetColumns(nColumns);
           m_wndMainToolBar.Invalidate();//控制各工具条显示更新
           ......//其它工具条控制代码,基本相同
        }
    }
6.3.11 工具条的属性控制
    WIN95/98中的鼠标右键弹出属性表功能具有很强的功能特色,很多应用程序中都对各种功能进行了属性控制设置,给应用程序中的工具条增加属性控制功能更具有现实意义。在工具条的属性表中可以设置工具栏的消隐与显示、工具条按钮的排序和其它各种控制功能,这要根据应用程序的需要来确定。这里以控制工具条的显示与消隐为例,详细阐述其实现的具体步骤:
    (1)首先打开资源列表中的菜单资源,利用"Insert->Resource->Menu"增加菜单资源IDR_TOOLBAR,在菜单中建立四个工具条菜单选项,并为各菜单选项设置ID标识和菜单项名,注意将各菜单选项标识符设置为与工具条名称完全相同的控制符,如本例程序中主控工具条ID为IDR_wndMainToolBar,那么控制主控工具条的菜单选项ID标识符也必须是IDR_wndMainToolBar,这样设置后可以使用MFC 类库中的提供的功能来控制工具条的显示与消隐、菜单项检查状态与非检查状态。
    (2)然后利用类向导ClassWizard 为应用程序主框架窗口增加解释消息PreTranslateMessage处理函数;
    (3)在应用程序实现文件MainFrm.cpp中完善解释消息函数:
    BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
    {    if (pMsg->message==WM_RBUTTONDOWN){
         CWnd* pWnd=CWnd::FromHandlePermanent(pMsg->hwnd);
         CControlBar* pBar=DYNAMIC_DOWNCAST(CControlBar,pWnd);//取得控制条句柄
         if (pBar!=NULL){
            CMenu Menu;//建立弹出式菜单
            CPoint pt; file://鼠标指针位置
            pt.x = LOWORD(pMsg->lParam);
            pt.y = HIWORD(pMsg->lParam);
            pBar->ClientToScreen(&pt);//转换成屏幕坐标
            if (Menu.LoadMenu(IDR_TOOLBAR)){//调入菜单资源
               CMenu* pSubMenu = Menu.GetSubMenu(0);//取得选项
               if (pSubMenu!=NULL){//跟踪菜单以取得输入
                  pSubMenu->TrackPopupMenu(TPM_LEFTALIGN|
          TPM_RIGHTBUTTON,pt.x,pt.y,this);
               }
             }
          }
        }
        return CFrameWnd::PreTranslateMessage(pMsg);
    }
    (4)在消息映射函数后增加
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
        file://{{AFX_MSG_MAP(CMainFrame)
        ......//其它消息映射函数
        file://}}AFX_MSG_MAP
        // 增加扩展命令消息和更新消息映射,利用现成MFC函数更新菜单
        ON_UPDATE_COMMAND_UI(IDR_MAINTOOLBAR,OnUpdateControlBarMenu)
        ON_COMMAND_EX(IDR_MAINTOOLBAR,OnBarCheck)
        ......//其它工具条映射函数基本相同,只有标识不同
    END_MESSAGE_MAP()
    (5)重要的程序设计技巧步骤
上述步骤1和步骤4是实现工具条属性菜单有效控制的最关键步骤,如果不在步骤1中将菜单ID设置成工具条的ID,或者不在步骤4中设置相应的消息映射,都不可能实现工具条菜单与工具条状态的有效控制。工具条菜单中的其它属性功能可模仿实现。笔者实现的工具条控制演练示例程序结果如下:
              工具条演练示例结果


第7章 演练CProgress
7.1 进度条的主要功能
    进度条控制(Progress Control)主要用来进行数据读写、文件拷贝和磁盘格式等操作时的工作进度提示情况,如安装程序等,伴随工作进度的进展,进度条的矩形区域从左到右利用当前活动窗口标题条的颜色来不断填充。
    进度条控制在MFC类库中的封装类为CProgressCtrl,通常仅作为输出类控制,所以其操作主要是设置进度条的范围和当前位置,并不断地更新当前位置。进度条的范围用来表示整个操作过程的时间长度,当前位置表示完成情况的当前时刻。SetRange()函数用来设置范围,初始范围为0-100,SetPos()函数用来设置当前位置,初始值为0,SetStep()函数用来设置步长,初始步长为10,StepIt()函数用来按照当前步长更新位置,OffsetPos()函数用来直接将当前位置移动一段距离。如果范围或位置发生变化,那么进度条将自动重绘进度区域来及时反映当前工作的进展情况。
    进度条的对象结构
    进度条控制的建立方法
    CProgressCtrl &ProgressCtrl  建立进度条控制对象结构
    Create                       建立进度条控制对象并绑定对象
    进度条控制类CprogressCtrl::Create的调用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
    其中参数dwStyle用来确定进度条控制的控制风格;参数rect用来确定进度条控制的大小和位置;参数pParentWnd用来确定进度条父窗口指针;参数nID用来确定进度条控制的控制符ID值。
7.2 进度条控制的类属性
    进度条控制的类属性包括设置进度条最大最小控制范围SetRange、设置进度条当前位置    SetPos、设置进度条当前位置偏移值OffsetPos和设置进度条控制增量值SetStep。
7.3 进度条控制的操作方法
    进度条控制的操作方法主要是使进度条控制并重绘进度条的StepIt函数。
进度条控制的应用技巧示例
    1、利用应用程序向导AppWizard生成基于对象框的应用程序CProgDlg;
    2、在对话框中设置进度条和静态文本控制,其ID分别为IDC_PROG和IDCPERCENT;
    在对话框初始代码中增加控制的范围和位置:
    在ProgDlg.h中设置两个数据成员,用来表示进度条的最大值和步长:
    file://ProgDlg.h
class CProgDlg:public Cdialog
{ ......//其它代码
public:
int m_nMax,m_nStep;
...... file://其它代码
}
    (2)在ProgDlg.cpp中设置初始状态
BOOL  CProgDlg::OnInitDialog()
{ Cdialog::OnInitDialog();
......//其它代码
file://TODO:Add extra initialization here
CProgressCtrl *pProgCtrl=(CProgressCtrl*)GetDlgItem(IDC_PROG);
pProgCtrl->SetRange(0,200);//设置进度条范围
......//其它代码
m_nMax=200;
m_nStep=10;
SetTimer(1,1000,NULL);//设置进度条更新时钟
return TRUE;
}
    (3)完善WM_TIMER消息处理,使进度条按照当前步长进行更新,同时完成进度条的百分比显示:
void CProgDlg::OnTimer(UINT nIDEvent)
{ file://TODO:Add your message handler
CProgressCtrl *pProgCtrl=(CProgressCtrl*)GetDlgItem(IDC_PROG);
int nPrePos=pProgCtrl->StepIt();//取得更新前位置
char test[10];
int nPercent=(int)(((nPrePos+m_nStep)/m_nMax*100+0.5);
wsprintf(test,%d%%,nPercent);
GetDlgItem(IDC_PERCENT)->SetWindowText(text);
Cdialog::OnTimer(nIDEvent);
}


第8章 演练CSlider
    滑动条控制(Slider Control)也叫轨道条控制,其主要是用一个带有轨道和滑标的小窗口以及窗口上的刻度,来让用户选择一个离散数据或一个连续的数值区间。通过鼠标或键盘来进行数据的选择操作,这在WIN98/95中的很多应用程序中都可以看到,如控制面板中的鼠标等,滑动条既可以是水平方式的也可以是垂直方式的。滑动条控制的风格如下:
    TBS_HORZ    滑动条是水平方向的
    TBS_VERT    滑动条是垂直方向的
    TBS_LEFT    滑动条位于窗口左侧
    TBS_RIGHT   滑动条位于窗口右侧
    TBS_TOP     滑动条位于窗口顶部
    TBS_BOTTOM  滑动条位于窗口底部
    TBS_BOTH    滑动条位于窗口两侧
    TBS_AUTOTICKS滑动条具有刻度,默认
    TBS_NOTICKS  滑动条不具有刻度
    滑动条的刻度条在每一个数值位置显示一个刻度标记,如果在滑动条上显示某一数值选择区间,则应使用风格TBS_ENABLESELRANGE,此时选择区间两个不再是刻度标记,而是一个小的三角形符号。另外,使用风格TBS_NOTHUMB会使滑标消隐起来。
    滑动条控制在MFC类库中被封装为CSliderCtrl控制,其主要操作是设置刻度范围、绘制刻度标记、设置选择范围和当前滑标位置等。当用户进行交互操作时,滑动条控制将向其父窗口发送消息WM_HSCROLL,所以在应用程序中应重载父窗口的OnHScroll()成员函数,以便对消息进行正确处理系统发送的通知代码、滑标位置和指向CSliderCtrl对象的指针等。由于考虑到和水平卷动杆公用同一个成员函数,OnHScroll()函数参数表中的指针变量被定义为CScrollBar*类型,由于实际上消息是由滑动条产生的,所以在程序中必须把这个指针变量强制转换为CSliderCtrl*类型。滑动条和卷动杆的消息代码和含义都非常类似如TB_BOTTOM等,所以这种处理方法比较合理。SetRange()函数用来设置范围,SetPos()函数用来设置当前位置。
8.1 滑动条控制的对象结构
    滑动条控制的建立方法
    CsliderCtrl &SliderCtrl  建立滑动条控制对象结构
    Create                   建立滑动条控制对象并绑定对象
    滑动条控制类CSliderCtrl::Create的调用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
    其中参数dwStyle用来确定滑动条控制风格;参数rect用来确定滑动条控制的大小和位置;参数pParentWnd用来确定滑动条控制的父窗口指针;参数nID用来确定滑动条控制的控制符ID值。
    2、滑动条控制的类属性
    滑动条控制对象的类属性包括取得滑动条大小GetLineSize、设置滑动条大小SetLineSize、取得滑动条页大小GetPageSize、设置滑动条页大小SetPageSize、取得滑动条最大位置GetRangeMax、取得滑动条最小位置GetRangeMin、取得滑动条范围GetRange、设置滑块最小位置SetRangeMin、设置滑块最大位置SetRangeMax、设置滑动条范围SetRange、取得滑块当前位置GetSelection、设置滑块当前位置SetSelection、取得滑动条当前位置GetPos和设置滑动条当前位置SetPos等。
    3、滑动条控制的操作方法
    滑动条控制的操作方法包括清除滑动条当前选择ClearSel、验证滑动条当前位置是否在最大最小位置之间VerifyPos和清除当前刻度标志ClearTics。
滑动条控制的应用技巧示例
    1、利用应用程序向导AppWizard生成基于对象框的应用程序CSlidDlg;
    2、在对话框中设置滑动条控制,其ID为IDC_SLIDER;
    3、在对话框初始代码中增加控制的范围和位置:
    (1)在SlidDlg.h中设置数据成员,用来表示滑动条的当前值:
file://SlidDlg.h
class CSlidDlg:public Cdialog
{ ......//其它代码
public:
int m_nCur;
......//其它代码
}
    (2)在SlidDlg.cpp中设置初始状态
BOOL  CSlidDlg::OnInitDialog()
{ Cdialog::OnInitDialog();
......//其它代码
file://TODO:Add extra initialization here
CSliderCtrl *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
pSlidCtrl->SetRange(1,5,TRUE);//设置滑动条范围
pSlidCtrl->SetPos(2);//设置滑动条位置
......//其它代码
return TRUE;
}
    (3)完善滑动条的消息处理,利用类向导ClassWizard增加对话框窗口的WM_HSCROLL消息处理函数,并取得滑标所指位置值:
void CSlidDlg::OnHScroll(UINT nSBCode,UINT nPos,CScrollBar *pScrollBar)
{ file://TODO:Add your message handler
Cdialog::OnHScroll(nSBCode,nPos,pScrollBar);
CSliderCtrl *pSlidCtrl=(CSliderCtrl*)GetDlgItem(IDC_SLLIDER);
m_nCur=pSlidCtrl->GetPos();//取得当前位置值
}


第9章 演练CSpin
9.1 旋转按钮控制的主要功能
    旋转按钮控制(Spin Button Control)又称为上下控制(Up Down Control),其主要功能是利用一对标有相反方向箭头的小按钮,通过点击它来在一定范围内改变当前的数值。旋转按钮控制的当前值通常显示在一个称为伙伴窗口(Buddy Window)的控制中,可以是一个编辑框等。
    与其它控制一样,可以通过设置旋转按钮的风格来控制其显示外观。其风格如下:
    UDS_HORZ        旋转按钮是水平方向的
    UDS_VERT        旋转按钮是垂直方向的
    UDS_ALIGNLEFT   旋转按钮位于伙伴窗口的左侧
    UDS_ALIGNRIGHT  旋转按钮位于伙伴窗口的右侧
    UDS_AUTOBUDDY   把旋转按钮的伙伴窗口设置为对话框中的顺序控制,即TAB顺序前一个控    制
    UDS_SETBUDDYINT 旋转按钮当前值改变时自动改变伙伴窗口标题所显示的数值
    UDS_NOTHOUSANDS 取消显示的数字中每三位间的“,”分隔符
    UDS_WRAP        旋转按钮的当前值超出最大(最小)值时自动回绕到最小(最大)值
    UDS_ARROWKEYS   可以让用户用光标键来改变当前值
    旋转按钮也可以不在伙伴窗口的任何一侧。如果位于伙伴窗口的一侧,应适当减少伙伴窗口的宽度以容纳下旋转按钮。
    旋转按钮控制在MFC类库中被封装为CSpinButtonCtrl类,其操作主要是获取和设置旋转按钮的变化范围、当前数值、伙伴窗口、伙伴窗口显示当前数据的数值基十进制还是十六进制和用户按住按钮时数值变化速度的加速度等。SetRange()函数用来设置范围,SetPos()函数用来设置当前位置。
9.2 旋转按钮控制的对象结构
    1、旋转按钮控制的建立方法
    CspinButtonCtrl &SpinButtonCtrl 建立旋转按钮控制对象结构
    Create       建立旋转按钮控制对象并绑定对象
    旋转按钮控制类CSpinButtonCtrl::Create的调用格式如下:
    BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID );
    其中参数dwStyle用来确定旋转按钮控制的风格;参数rect用来确定旋转按钮控制的大小和    位置;参数pParentWnd用来确定父窗口指针;参数nID用来确定旋转按钮的控制符ID值。
    2、旋转按钮控制的类属性
    旋转按钮控制的类属性包括设置加速键SetAccel、取得加速键GetAccel、设置基数SetBase、取得基数GetBase、设置伙伴窗口SetBuddy、取得伙伴窗口GetBuddy、设置当前位置SetPos、取得当前位置GetPos、设置上限下限值SetRange和取得上限下限值GetRange等。
9.3 旋转按钮控制的应用技巧示例
    1、利用应用程序向导AppWizard生成基于对象框的应用程序CSpinDlg;
    2、在对话框中设置旋转按钮控制和编辑框控制,其ID分别为IDC_SPIN和IDC_EDIT;
    在对话框初始代码中增加控制的范围和位置:
    (1)在SpinDlg.h中设置数据成员,用来表示旋转按钮的步长值:
file://SlidDlg.h
class CSlidDlg:public Cdialog
{ ......//其它代码
public:
int m_nStep;
......//其它代码
}
    (2)在SpinDlg.cpp中设置初始状态
BOOL  CSlidDlg::OnInitDialog()
{ Cdialog::OnInitDialog();
......//其它代码
file://TODO:Add extra initialization here
CSpinButtonCtrl *pSpinCtrl=(CSpinButtonCtrl*)GetDlgItem(IDC_SPIN);
pSpinCtrl->SetRange(-50,50);//设置旋转按钮范围
pSpinCtrl->SetPos(10);//设置旋转按钮位置
......//其它代码
return TRUE;
}
    (3)完善旋转按钮的消息处理,利用类向导ClassWizard增加对编辑框的EN_CHANGE消息处理函数,以使伙伴窗口编辑框的数据随着旋转按钮一起变化:
void CSPinDlg::OnChangeEdit()
{ file://TODO:Add your message handler
m_nStep=GetDlgItemInt(IDC_EDIT);
......//进行其它处理
}


第10章 演练CStatusBar
10.1 状态条控制的主要功能
    状态条控制(Status Bar Control)比较容易理解,使用起来也比较简单。状态条是位于父窗口底部的一个水平子窗口,它可以被分成多个显示信息的小区域。其MFC中封装的CstatusBarCtrl控制类提供了应用的基本方法。
10.2 状态条控制的对象结构
    状态条控制的建立方法
    CStatusBarCtrl &StatusBarCtrl  建立状态条控制对象结构
    Create                         建立状态条控制对象并绑定
    状态条控制类CstatusBarCtrl::Create的调用格式如下:
    BOOL Create( DWORD dwStyle,const RECT& rect,CWnd* pParentWnd,UINT nID);
    其中参数dwStyle用来确定状态条的控制风格;参数rect用来确定状态条窗口的大小和位置;参数pParentWnd用来确定状态条父窗口的指针;nID用来确定状态条控制的标识符。
    状态条控制风格可以是下列值的组合:CCS_BOTTOM、CCS_NODIVIDER、CCS_NOHILITE、CCS_NOMOVEY、CCS_NOPARENTALIGN、CCS_NORESIZE和CCS_TOP等,具体内容和含义请见工具条控制中的有关部分。
    2、状态条控制的类属性
    状态条控制类属性包括设置给定部分显示文本SetText、取得给定部分的文本GetText、设置状态条区域划分数及其每部分的右边坐标SetParts、取得状态条区域划分数量GetParts、取得状态条的水平和垂直宽度GetBorders和取得状态条矩形区域GetRect。
10.3 状态条控制的应用技巧
    状态条控制除可以显示一定的帮助和提示信息外,还可以实现响应鼠标输入等功能。这里以在状态条上显示鼠标移动坐标为例,具体说明其应用技巧。
     利用应用程序向导生成的程序代码中,状态条作为主窗口的子窗口,其具有一个AFX_IDW_STATUS _BAR标识符,通过它调用函数GetDescendantWindow()和AfxGetMainWnd(),就可以取得状态条窗口的指针。由于基于文档的应用程序在建立时就具有状态条区域,所以只要利用类向导简单地加入鼠标移动消息处理功能函数和下述函数代码,就可以实现这一功能:
 Void CTestView::OnMouseMove(UINT nFlags,Cpoint point)
 {
  CclientDC dc(this);//建立设备文本
  OnPrepareDC(&dc,NULL);//设备映射处理
  dc.DPtoLP(&point);//鼠标指针转换
  char text[128];
  CstatusBar *pStatus=(CstatusBar *)AfxGetApp()->m_pMainWnd->
       GetDescendanWindow(AFX_IDW_STATUS_BAR);//取得窗口指针
  If(pStatus){//如果存在显示鼠标坐标
   Sprintf(text,”X坐标=%4d,Y坐标=%4d”,point.x,point.y);
   pStatus->SetPaneText(0,text);}
  CscrollView::OnMouseMove(nFlags,point); 
  }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值