如何在VC5下实现自己的定制控件

翻译|其它|编辑:郝浩|2006-08-01 16:00:00.000|阅读 1932 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>


首先利用应用程序向导AppWizard 生成应用程序框架,如本文的应用程序项目名称为ctrltest,应用程序根据需要选择其基类,可以是基于对话或文档的,本文是选择基于文档的,并具有默认的下拉菜单和工具条等功能;然后编辑菜单资源,设置响应定制功能菜单项名称、ID标识;利用类向导ClassWizard 为菜单项映射命令和更新消息函数;为定制功能增加所使用的图形资源和对话框等资源;最后为定制功能增加所需的成员变量和成员函数定义。
  一、如何实现按钮的定制功能
  在定制按钮功能时,定制前必须设计好按钮所在的标准对话及定制按钮在对话框中所对应的标准按钮,因为定制按钮实际上是标准按钮的一种特殊情况,只是按钮上显示的信息由用户来定制,而其余的消息映射响应和更新方法均相同,所以定制按钮实际上也是定制按钮上各种显示信息的过程。

  (一)利用LoadBitmaps函数定制方法
  1、在资源对话窗口中增加按钮所需的按下、抬起和选中状态对应的位图及其ID标识;
  2、在资源对话窗口中增加按钮所在的对话框和标准按钮及其所对应的各种ID标识;
  3、利用类向导ClassWizard增加新类CBMTest1Dlg,其基类选择基于对话框CDialog的类型,并设置其头文件为Bbutton.cpp,但不设置其实现文件名;
  4、在实现文件Bbutton.cpp中进行如下代码完善:
   ......//其它代码
   class CBMTest1Dlg : public CDialog
   {//完善类控制代码
       protected:
          CBitmapButton button1,button2;//定义按钮
       public:
         //{{AFX_DATA(CBMTest1Dlg)
       enum {IDD=IDM_TEST_BITMAP_BUTTON1};//对话框标识
         //}}AFX_DATA
       CBMTest1Dlg(); //类实现文件
       BOOL OnInitDialog();//对话框初始化
       //{{AFX_MSG(CBMTest1Dlg)
       //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
   };
   ......//其它代码
   CBMTest1Dlg::CBMTest1Dlg()
   : CDialog(CBMTest1Dlg::IDD)
   { //调入按钮位图资源函数
     if(!button1.LoadBitmaps(_T(“Image1Up"),//按钮一所需位图
        _T(“Image1Down"),_T(“Image1Focus"))||//按下、抬起和选中
         !button2.LoadBitmaps(_T(“Image2Up"), //按钮二所需位图
        _T(“Image2Down"), _T(“Image2Focus")))
           { TRACE0(“按钮所需位图调入失败!\n");
             AfxThrowResourceException();
         }
      }
   BOOL CBMTest1Dlg::OnInitDialog()
   { //将对话框中按钮标识与位图连接
     VERIFY(button1.SubclassDlgItem(IDOK, this));
     button1.SizeToContent();//使按钮大小适应位图
     VERIFY(button2.SubclassDlgItem(IDCANCEL, this));
     button2.SizeToContent();
     return TRUE;
   }

  (二)利用AutoLoad函数定制方法

  1、在资源对话窗口中增加按钮所需的按下、抬起和选中等状态所对应的位图及其ID标识,注意位图的ID标识必须与对话框中按钮的ID标识相对应,即如果按钮的ID标识为IDOK,那么位图的ID标识必须为OKN、OKU、OKF和OKX,这是该方法实现的关键;
  2、在资源对话窗口中增加按钮所在的对话框和标准按钮及其所对应的各种ID标识,注意按钮的ID标识必须与位图对应,如果相应位图的标识为OKN等,则按钮ID标识必须为IDOK或ID_OK;
  3、利用类向导ClassWizard增加新类CBMTest1Dlg,其基类选择基于对话框CDialog的类型,并设置其头文件为Bbutton.cpp,但不设置其实现文件名;
  4、在实现文件Bbutton.cpp中进行如下代码完善:
   class CBMTest2Dlg : public CDialog
   {//完善按钮类控制代码
      protected:
        CBitmapButton buttonOk,buttonCan;//定义按钮
      public:
      //{{AFX_DATA(CBMTest2Dlg)
      enum {IDD=IDM_TEST_BITMAP_BUTTON2};//按钮对话框标识
      //}}AFX_DATA
      CBMTest2Dlg():CDialog(CBMTest2Dlg::IDD){}//映射类
      BOOL OnInitDialog();//初始化对话框
      //{{AFX_MSG(CBMTest2Dlg)
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
   };
   ......//其它代码
   BOOL CBMTest2Dlg::OnInitDialog()
   { //完善初始化函数
      VERIFY(buttons[i].AutoLoad(IDOK,this));//调入位图
      VERIFY(buttons[i].AutoLoad(IDCANCEL,this));
      return TRUE;
   }

  (三)两种定制方法的主要区别

  上述两种定制方法的主要区别是,第一种方法位图资源和按钮的ID标识可以随意确定,而其代码相对来说比较复杂;第二种方法位图资源和按钮的ID标识必须统一,而其代码简单有效。但两种方法定制后的对话框调用与正常对话框的调用完全相同:

  CBMTest1Dlg dlg;//定义对话框一
  dlg.DoModal(); //调用对话框一

  二、如何实现菜单的定制功能

  定制菜单功能实际上是程序增加菜单项的绘制过程,这里以色彩菜单项为例进行介绍。其实现步骤如下:
  1、利用类向导ClassWizard生成定制菜单新类CColorMenu ,其基类选择为CMenu ,实现头文件为主程序头文件,实现文件为CUSTMENU,头文件中的类其代码如下:
   class CColorMenu : public CMenu
   {//定制菜单类代码
      public://增加菜单项等功能函数定义
      void AppendColorMenuItem(UINT nID,COLORREF color);
     virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
      CColorMenu();//构造函数
      virtual ~CColorMenu();//析构函数
   };
   并在头文件中的主程序类中增加成员变量和成员函数定义:
   class CTestWindow : public CFrameWnd
   {//主程序类中定义成员变量或函数
      public:
      void SetupMenus();//初始化菜单项
      protected:
      void AttachCustomMenu();//连接定制菜单
      CColorMenu m_colorMenu;//菜单控制成员变量和命令函数
      virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
      ......//其它代码
   }
  2、在主程序实现文件中增加如下代码:
   //在菜单设置函数中增加连接定制菜单函数
   void CTestWindow::SetupMenus()
   { //菜单设置函数
     ......//其它代码
     AttachCustomMenu(); //连接定制菜单
   }
   //在主程序初始化函数中增加控制代码
   BOOL CTestApp::InitInstance()
   { ......//其它代码
      pMainWnd->m_bAutoMenuEnable=FALSE;
      pMainWnd->SetupMenus();//设置菜单控制
      ......//其它代码
   }

  3、在菜单定制实现文件CUSTMENU.CPP中增加实现代码:
   CColorMenu::CColorMenu()
   { //构造函数中建立菜单
      VERIFY(CreateMenu());
   }
   CColorMenu::~CColorMenu()
   { //在析构函数中撤消
      Detach();
      ASSERT(m_hMenu==NULL);
   }
   void CColorMenu::AppendColorMenuItem(UINT nID,COLORREF color)
   { //增加菜单项函数
       VERIFY(AppendMenu(MF_ENABLED|MF_OWNERDRAW,
       nID,(LPCTSTR)color));
   }
   #define COLOR_BOX_WIDTH 20 //菜单项宽度
   #define COLOR_BOX_HEIGHT 20 //菜单项高度
  void CColorMenu::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
   { //设置菜单项宽度和高度
      lpMIS->itemWidth = COLOR_BOX_WIDTH;
      lpMIS->itemHeight = COLOR_BOX_HEIGHT;
   }
   void CColorMenu::DrawItem(LPDRAWITEMSTRUCT lpDIS)
   { //绘制菜单项函数
      CDC* pDC=CDC::FromHandle(lpDIS->hDC);
      COLORREF cr=(COLORREF)lpDIS->itemData;
      if (lpDIS->itemAction&ODA_DRAWENTIRE)
        { CBrush br(cr);//绘制正常状态彩色条
          pDC->FillRect(&lpDIS->rcItem,&br);
        }
      if((lpDIS->itemState&ODS_SELECTED)&&
    (lpDIS->itemAction&(ODA_SELECT|ODA_DRAWENTIRE)))
      { //绘制选中菜单项色彩条
         COLORREF crHilite = RGB(255-GetRValue(cr),
         255-GetGValue(cr),255-GetBValue(cr));
         CBrush br(crHilite);
         pDC->FrameRect(&lpDIS->rcItem,&br);
      }
      if (!(lpDIS->itemState&ODS_SELECTED) &&
       (lpDIS->itemAction&ODA_SELECT))
        { CBrush br(cr);//清除前次选中项的框
            pDC->FrameRect(&lpDIS->rcItem,&br);
        }
   }
   static COLORREF colors[]={//色彩条菜单项定义
   0x00000000, // 黑
   0x00FF0000, // 蓝
   0x0000FF00, // 绿
   0x00FFFF00, // 青
   0x000000FF, // 红
   0x00FF00FF, // 棕
   0x0000FFFF, // 黄
   0x00FFFFFF // 白
   };
   const int nColors=sizeof(colors)/sizeof(colors[0]);
   void CTestWindow::AttachCustomMenu()
      { //连接用户定制菜单
          for (int iColor=0;iColor   m_colorMenu.AppendColorMenuItem(IDS_COLOR_NAME_FIRST
          +iColor,colors[iColor]);
          CMenu* pMenuBar=GetMenu();//取得菜单控制
          ASSERT(pMenuBar!=NULL); //插入菜单项
          TCHAR szString[256];
         pMenuBar->GetMenuString(IDM_TEST_CUSTOM_MENU,//取得菜单串
          szString,sizeof(szString),MF_BYCOMMAND);
        VERIFY(GetMenu()->ModifyMenu(IDM_TEST_CUSTOM_MENU,//连接菜单
          MF_BYCOMMAND|MF_POPUP,(UINT)m_colorMenu.m_hMenu,szString));
      }
   BOOL CTestWindow::OnCommand(WPARAM wParam,LPARAM lParam)
      { //定制菜单项响应函数
        if (wParam=
        IDS_COLOR_NAME_FIRST+nColors)//判断选中菜单
        return CFrameWnd::OnCommand(wParam,lParam);
        CString strYouPicked;//判断选中颜色
        strYouPicked.LoadString(IDS_YOU_PICKED_COLOR);
        CString strColor;
        strColor.LoadString(wParam);
        CString strMsg;
        strMsg.Format(strYouPicked, (LPCTSTR)strColor);
        CString strMenuTest;
        strMenuTest.LoadString(IDS_MENU_TEST);
        MessageBox(strMsg,strMenuTest);
        return TRUE;
   }

  三、如何实现列表的定制功能

  列表功能是最常用的控制功能之一,所以实现它的定制技巧也具有很大的现实意义。其实现步骤如下:

  1、首先利用资源编辑器建立一个包含列表控件的对话框,并利用类向导ClassWizard为对话框生成新类CColorListBox,其头文件为custlist.cpp,实现文件不设置;
  2、在实现文件custlist.cpp中完善其类代码:
   class CColorListBox:public CListBox
   {//完善列表控制类代码
      public://类成员函数
      void AddColorItem(COLORREF color);
      virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
   };
  3、在实现文件custlist.cpp中完善各成员函数;
   void CColorListBox::AddColorItem(COLORREF color)
   { //增加表项,其为一个颜色值
      AddString((LPCTSTR) color);
   }
   #define COLOR_ITEM_HEIGHT 20 //列表的高度
   void CColorListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
   { //设置自绘表项的高度
      lpMIS->itemHeight = COLOR_ITEM_HEIGHT;
   }
   void CColorListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
   { //绘制列表的表项函数
       CDC* pDC=CDC::FromHandle(lpDIS->hDC);
       COLORREF cr=(COLORREF)lpDIS->itemData;
       if (lpDIS->itemAction&ODA_DRAWENTIRE){
       CBrush br(cr);//绘制正常色彩条
       pDC->FillRect(&lpDIS->rcItem,&br);
   }
   if ((lpDIS->itemState&ODS_SELECTED) &&
      (lpDIS->itemAction&(ODA_SELECT|ODA_DRAWENTIRE)))
   { //绘制选中项色彩条
       COLORREF crHilite=RGB(255-GetRValue(cr),
       255-GetGValue(cr),255-GetBValue(cr));
       CBrush br(crHilite);
       pDC->FrameRect(&lpDIS->rcItem,&br);
   }
   if (!(lpDIS->itemState&ODS_SELECTED)&&
   (lpDIS->itemAction&ODA_SELECT))
   { //清除前次选中项的框
       CBrush br(cr);
      pDC->FrameRect(&lpDIS->rcItem, &br);
    }
   }
  4、在实现文件custlist.cpp中可以像使用其它类一样使用新生成的定制列表类,其方法是首先设置类的控制成员变量m_colors,并设置相应的消息映射,最后完善其初始化函数:
   BOOL CCustListDlg::OnInitDialog()
   { //完善初始化函数,与子类控制连接
      VERIFY(m_colors.SubclassDlgItem(IDC_LISTBOX1,this));
      for(int red=0;red<=255;red+=255)//增加彩色条8项
      for(int green=0;green<=255;green+=255)
      for(int blue=0;blue<=255;blue+=255)
      m_colors.AddColorItem(RGB(red,green,blue));
      return TRUE;
   }
  只要掌握上述定制功能的实现技巧,就不难实现各种定制功能的其它类似用户界面,还可以实现其它常用控件的定制功能,为自己的应用程序增加各种独特风格,有效增强其专业特性。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP