创建WINDOWS XP样式的ActiveX按钮

原创 2002年10月08日 09:26:00
 

使用MFC向导来创建一个ActiveX控件是一件非常简单的事。这篇文章里我会向大家阐述了怎样在VC++里面创建一个类似WINDOWS XP样式的ActiveX按钮。

选择MFC ActiveX控件向导来创建一个新的工程,并命名为“XpButtonEx”。在ActiveX控件向导里有两步。在第一个对话框中选择一个控件,不要运行时间许可,源文件注释和帮助文件。在第二个对话框中选择“Activates When Visible, Insert Object对话框中选择“Available”,还有一个About对话框。当向导询问:“Which window class, if any, should this control subclass?”时选择“BUTTON”。点完成。向导会建立大约19个文件,有三个类:CxpButtonExApp, CxpButtonExCtrlCxpButtonExPropPage

现在打开类向导,并确认当前选定的是CxpButtonExCtrl。为WM_CREATE, WM_LBUTTONDOWN, WM_LBUTTONUP,WM_MOUSEMOVE添加消息映射。在Class观察表中右击CxpButtonExCtrl,然后添加虚函数:PreSubclassWindow。在PreSubclassWindow函数的COleControl::PreSubclassWindow()添加语句:ModifyStyle(0, BS_OWNERDRAW|BS_NOTIFY)。现在打开XpButtonEx.h,添加下列成员变量和函数:

public:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

CPen *pBoundryPen;

CPen *pInsideBoundryPenLeft;

CPen *pInsideBoundryPenTop;

CPen *pInsideBoundryPenRight;

CPen *pInsideBoundryPenBottom;

CPen *pOldPen;

CBrush *pFillActive;

CBrush *pFillInactive;

CBrush *pOldBrush;

BOOL m_bOverControl;

void DoGradientFill(CDC *pDC, CRect rect);

void DrawInsideBorder(CDC *pDC, CRect rect);

打开XpButtonEx.cpp。在构造函数CXpButtonExCtrl()添加下列代码:

m_bOverControl = FALSE;

  pBoundryPen = new CPen(PS_INSIDEFRAME|PS_SOLID,1,RGB(0,0,0));

  pInsideBoundryPenLeft = new CPen(PS_INSIDEFRAME|

      PS_SOLID,3,RGB(250,196,88));

  pInsideBoundryPenRight = new CPen(PS_INSIDEFRAME|

      PS_SOLID,3,RGB(251,202,106));

  pInsideBoundryPenTop = new CPen(PS_INSIDEFRAME|

      PS_SOLID,2,RGB(252,210,121));

  pInsideBoundryPenBottom = new CPen(PS_INSIDEFRAME|

      PS_SOLID,2,RGB(229,151,0));

  pFillActive = new CBrush(RGB(222,223,236));

  pFillInactive = new CBrush(RGB(222,223,236));

在析构函数~CXpButtonExCtrl()里删除对象:

pBoundryPen->DeleteObject();

  pFillActive->DeleteObject();

  pFillInactive->DeleteObject();

  pOldPen->DeleteObject();

  pOldBrush->DeleteObject();

  pInsideBoundryPenLeft->DeleteObject();

  pInsideBoundryPenRight->DeleteObject();

  pInsideBoundryPenBottom->DeleteObject();

  pInsideBoundryPenTop->DeleteObject();

XpButtonCtl.cpp中添加下列函数:

void CXpButtonExCtrl::DoGradientFill(CDC *pDC, CRect rect)

{

    CBrush* pBrush[64];

    for (int i=0; i<64; i++)

      pBrush[i] = new CBrush(RGB(253-(i/2),

                             253-(i/3), 

                             253-(i/4)));

    int nWidth = (rect.right) - (rect.left);

    int nHeight = (rect.bottom) - (rect.top);

    CRect rct;

 

    for (i=rect.top; i < nHeight+2; i++)

  {

        rct.SetRect (rect.left, i, nWidth+2, i + 1);

        pDC->FillRect (&rct, pBrush[(i * 63) / nHeight]);

    }

 

    for (i=0; i<64; i++)

        delete pBrush[i];

 

}

void CXpButtonExCtrl::DrawInsideBorder(CDC *pDC,CRect rect)

{

  pOldPen = pDC->SelectObject(pInsideBoundryPenLeft);

  pDC->MoveTo(rect.left,rect.bottom-3);

  pDC->LineTo(rect.left,rect.top+2);

  pDC->SelectObject(pInsideBoundryPenRight);

  pDC->MoveTo(rect.right-1,rect.bottom-3);

  pDC->LineTo(rect.right-1,rect.top+2);

  pDC->SelectObject(pInsideBoundryPenTop);

  pDC->MoveTo(rect.left+2,rect.top);

  pDC->LineTo(rect.right-2,rect.top);

  pDC->SelectObject(pInsideBoundryPenBottom);

  pDC->MoveTo(rect.left+2,rect.bottom);

  pDC->LineTo(rect.right-2,rect.bottom);

  pDC->SelectObject(pOldPen);

}

现在回到OnOcmCommand(),并在返回0值以前添加下列switch

...

switch(wNotifyCode)

{

  case BN_CLICKED:  // // The click event should be fired

                    // when the button is clicked.

          click事件应该在按钮按下时被激活

          FireClick();

   break;

}

我们使用Boolean变量m_bOverControll来跟踪鼠标位置。当鼠标在按钮上时,按钮接收到WM_MOUSEMOVE。将OnMouseMove的代码作如下改动:

void CXpButtonExCtrl::OnMouseMove(UINT nFlags, CPoint point)

{

  // TODO: Add your message handler code

  // here and/or call default.

 

  COleControl::OnMouseMove(nFlags, point);

  if(!m_bOverControl)

  {

   m_bOverControl = TRUE;

   Invalidate(FALSE);

   TRACKMOUSEEVENT tm;

   tm.cbSize = sizeof(tm);

   tm.dwFlags = TME_LEAVE;

   tm.hwndTrack = this->m_hWnd;

   ::_TrackMouseEvent(&tm);

  }

}

现在,为了检测鼠标什么时候离开按钮,我们必须手动添加下列消息句柄。在XpButtonExCtl.h中添加:LRESULT OnMouseLeave(WPARAM, LPARAM);XpButtonExCtl.cpp中添加:ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)。在XpButtonExCtl.cpp中添加函数:LRESULT CXpButtonExCtrl::OnMouseLeave(WPARAM, LPARAM)

{

   m_bOverControl = FALSE;

  Invalidate(FALSE);

  return 0;

}

现在,为了画出按钮,我们需要手动为OCM_DRAWITEM消息添加句柄。在 XpButtonExCtl.h 里添加LRESULT OnOcmDrawItem(WPARAM wParam, LPARAM lParam)。在XpButtonExCtl.cpp里添加add ON_MESSAGE(OCM_DRAWITEM, OnOcmDrawItem)。在XpButtonEx.cpp里添加函数OnOcmDrawItem

LRESULT CXpButtonExCtrl::OnOcmDrawItem(WPARAM wParam,

                                       LPARAM lParam)

{

  UINT nIDCtl = (UINT) wParam;

  LPDRAWITEMSTRUCT lpDrawItemStruct = 

                            (LPDRAWITEMSTRUCT) lParam;

  CDC* pDC   = CDC::FromHandle(lpDrawItemStruct->hDC);

  CRect rect = lpDrawItemStruct->rcItem;

  UINT state = lpDrawItemStruct->itemState;

 

    // 画出控件的边缘 

  CPoint pt;

  pt.x = 10;

  pt.y = 10;

  

    pOldPen = pDC->SelectObject(pBoundryPen);

    if (state & ODS_SELECTED)

       pDC->RoundRect(rect,pt);

    else

       pDC->RoundRect(rect,pt);

    pDC->SelectObject(pOldPen);

    //按照按钮边缘的大小缩小画图区域    rect.DeflateRect( CSize(GetSystemMetrics(SM_CXEDGE),

                      GetSystemMetrics(SM_CYEDGE)));

    //如果必要填充内部颜色

   if (m_bOverControl)

   {

      pOldBrush = pDC->SelectObject(pFillActive);

      DoGradientFill(pDC,rect);

      DrawInsideBorder(pDC,rect);

   }

   else

   {

      pOldBrush = pDC->SelectObject(pFillInactive);

      DoGradientFill(pDC,rect);

   }

   pDC->SelectObject(pOldBrush);

    

      //画出文本 

    if (!m_title.IsEmpty())

    {

        CSize Extent = pDC->GetTextExtent(m_title/*strText*/);

        CPoint pt( rect.CenterPoint().x - Extent.cx/2, 

        rect.CenterPoint().y - Extent.cy/2 );

 

        if (state & ODS_SELECTED) 

            pt.Offset(1,1);

 

        int nMode = pDC->SetBkMode(TRANSPARENT);

        CFont *pOldFont = SelectStockFont( pDC );

 

        if (state & ODS_DISABLED)

            pDC->DrawState( pt,

                            Extent,

                            m_title,

                            DSS_DISABLED,

                            TRUE,

                            0, 

                            (HBRUSH)NULL);

        else

            pDC->TextOut(pt.x, pt.y, m_title);

pDC->SelectObject(pOldFont);

        pDC->SetBkMode(nMode);

    }

  return 0;

}

现在我们将对我们的ActiveX Control添加两个属性。一个是Tile,另一个是Font。打开类向导,选择自动控制(Automation)标签。确认所选类是CxpButtonEx。点击“Add Property”按钮。在Add Property对话框中,给它一个外部名称(如“title”)并选择类型为Cstring。接受默认的变量和函数。点击OK关闭类向导对话框。。在XpButtonExCtl.cpp里的DoPropExchange函数TODO注释后面添加下列语句:

PX_String( pPX, _T("title"), m_title, _T("Caption"));

现在到Resourses观察标签下打开对话框模板IDD_PROPPAGE_XPBUTTONEX,删除TODO:...声明。增加一个编辑框IDC_TITLE,现在打开类向导,选择成员变量标签。选择类CxpButtonExPropPage,选择IDC_TITLE然后点“Add Variable”。在成员变量对话框中,给一个成员变量赋名(m_title), Category - Value, Variable Type  Cstring。给Optional Property一个名字(如title)。点击OK关闭类向导对话框。

现在我们可以添加Font的一般属性。打开类向导选择自动控制标签。确认所选类名是CxpButtonEx。点击“Add Property”按钮。在组合框中选择外部名称(如font)。点击OK关闭类向导对话框。现在我们为font设置一个属性页。这真的很简单,因为我们可以使用先前写好的属性页。打开XpButtonExCtl.cpp,找到如下代码:

BEGIN_PROPPAGEIDS(CDierollCtrl, 1)

  PROPPAGEID(CDierollPropPage::guid)

END_PROPPAGEIDS(CdierollCtrl

在这里改变计数到2,添加另一个PROPPAGEID。新写的代码象这样:

BEGIN_PROPPAGEIDS(CDierollCtrl, 2)

  PROPPAGEID(CDierollPropPage::guid)

  PROPPAGEID(CLSID_CFontPropPage)

END_PROPPAGEIDS(CDierollCtrl)

现在我们的控件终于完成了。到另一个ActiveX测试器中去测试它吧!

 

Windows API BUTTON篇学习笔记

下面是一些关于windows下的按钮控件的一些东东,希望对大家有用  常用的按钮有普通按钮、单选按钮、复选框,和组框,普通按钮作用是帮助用户触发指定动作;单选按钮一般各选项之间存在互斥性;复选框用来显...
  • hellosijian
  • hellosijian
  • 2011年07月18日 23:18
  • 15230

MFC 实现XP样式

对Visual C++ 6.0的程序实现XP样式: 它不仅对Visual C++ 6.0写的程序管用,对其它以前已经编写的在XP界面下显示为旧样式的程序同样有效。将下面文本保存为yo...
  • lingtianyulong
  • lingtianyulong
  • 2014年03月26日 16:47
  • 938

让MFC程序具有XP风格的按钮及界面

VC++6.0编译生成的MFC程序没有XP风格的界面,显得不是太美观,下面,我们可以采取两种方法来让其显示XP风格的界面。   第一种方法比较简单,只需要一个小小的文件就可以。但是有一个缺点,就是这个...
  • zjccsg
  • zjccsg
  • 2016年07月16日 19:57
  • 539

让 VB6 开发的程序拥有视觉样式( XP 风格),VC++6.0 同样适用

让 VB6 开发的程序拥有视觉样式( XP 风格),VC++6.0 同样适用。     相信用 VB6 或 VC6 开发过程序的朋友都曾郁闷过吧,VB6 或 VC6 做的程序都没有视觉样式(XP...
  • ROVAST
  • ROVAST
  • 2014年05月19日 16:58
  • 2398

VC程序中Windows XP风格程序界面的实现

文章原创,转载请注明出处 默认情况下用MVC++98创建的MFC应用程序的界面使用5.82版本的ComCtrl32.dll中控件,使得其风格为Windows 2000系统的风格, 看上去绘制得比较...
  • menglongbor
  • menglongbor
  • 2013年01月17日 16:19
  • 3077

xp样式按钮

using System;using System.Windows;using System.Drawing;using System.Drawing.Drawing2D;using System.W...
  • moonshineidolon
  • moonshineidolon
  • 2008年01月11日 14:17
  • 495

使用 Windows XP 的外观风格

目录 简介 ComCtl32.dll 版本 6 外观风格任务 在未使用第三方扩展的应用程序中使用 ComCtl32.dll 版本 6 在使用扩展、插件或进程内运行...
  • whchen
  • whchen
  • 2006年08月21日 08:25
  • 1765

C# xp样式按钮

using System; using System.Windows; using System.Drawing; using System.Drawing.Drawing2D; using Syst...
  • yaojian19851213
  • yaojian19851213
  • 2008年06月24日 10:33
  • 1291

easyui创建链接按钮(Link Button)

easyui创建链接按钮(Link Button) 原文地址:http://www.expert58.com/news/1986.html Normally a button is creat...
  • u010328895
  • u010328895
  • 2013年04月28日 10:32
  • 536

Windows button控件(按钮控件)

按钮既是标准控件,也是子窗口,窗口类名是button。 Button 控件样式以BS开头,常用的有: 样式 说明 BS_LEFT 文本居左。 BS_...
  • softn
  • softn
  • 2016年06月20日 06:38
  • 885
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:创建WINDOWS XP样式的ActiveX按钮
举报原因:
原因补充:

(最多只允许输入30个字)