分享
 
 
 

创建WINDOWS XP样式的ActiveX按钮

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

使用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:

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测试器中去测试它吧!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有