创建WINDOWS XP样式的ActiveX按钮
2002-10-08 09:26
537 查看
使用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, CxpButtonExCtrl和CxpButtonExPropPage。
现在打开类向导,并确认当前选定的是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 Powershell创建对象
- 千年零一虫
- ATL实现Connection Point的一种简单的方法
- 独具量身定做特色的管理软件--数据大师
- delphi中的时间操作技术(2)
- 怎样为任何控件和区域添加提示信息:用自己封装的CTip类
- 移植到 Windows 2000 和 COM+
- 使用C#开发COM+组件
- 关于win2000安装的2个问题
- Inside Java2 SDK Source Internal 深入Java2 SDK原始码(一) Java2 SDK原始码概观
- Java 2 Micro Edition简介(四)
- 利用Java 编写手机应用程序 Motorola iDEN篇
- 调试利器-----------------------DebugTrace for Windows简介
- DebugTrace 使用说明
- WIN32 SDK - 捕获鼠标离开和滞留等事件
- 用VxD技术设计网络计费系统
- 让应用程序禁止Windows屏幕保护
- 统一部署 PowerShell 5.1