当前位置:C++技术网 > 资讯 > VC++创建自定义按钮类实现的分析

VC++创建自定义按钮类实现的分析

更新时间:2016-03-30 14:34:13浏览次数:1+次

对于自定义按钮的实现,需要重载或定义几个函数,下面列举下:CButton::Create,presubclasswindow,oncreate,drawitem等几个函数。
下面,我们来看看我们自定义的Create函数,原本来讲,对于Create函数,我们只需定义按钮类的对象,而后引用一个Create函数就行了。可是,既然我们都自定义按钮类了,那么,我们就自定义其Create函数。

首先,我们派生一个继承自CButton类的CMybutton类,而后在派生类中,定义一个HRGN变量m_hRgn;然后,我们在构造函数中,初始化这个变量,初始化为0.

BOOL CMybutton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID)
{
	// store region in member variable
	DeleteObject(m_hRgn);
	m_hRgn = CreateRectRgn(0, 0, 31, 31);
	CRect box(0, 0, 0, 0);
	if (m_hRgn != 0) 
		CombineRgn(m_hRgn, hRgn, 0, RGN_COPY);//拷贝hRgn;

	// make sure that region bounding rect is located in (0, 0)
	GetRgnBox(m_hRgn, &box);
	OffsetRgn(m_hRgn, -box.left, -box.top);//保证区域的左顶点在原点;
	GetRgnBox(m_hRgn, &box);

	// update position of region center for caption output
	m_CenterPoint = CPoint(box.left + box.Width() /2 , box.top + box.Height() /2);//找到区域的中点坐标,进而平移过去
	box.OffsetRect(point);

	return CButton::Create(lpszCaption, dwStyle, box, pParentWnd, nID);
}
既然要自定义按钮,我们需要修改按钮的样式,设置按钮样式为BS_OWNERDRAW方能自定义按钮。那么,我们就可以在presubclasswindow函数中设置。
void CMybutton::PreSubclassWindow() 
{
	// change window style to allow owner draw
	ModifyStyle(0, BS_OWNERDRAW | BS_PUSHBUTTON);	
	CButton::PreSubclassWindow();
}
当我们修改按钮样式为自绘时,就会调用DrawItem函数。这个函数实现的是按钮等控件的自绘,而OnDrawItem函数则是实现父类对子类的绘制。下面,我们设计DrawItem函数:

void CMybutton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

	// TODO:  添加您的代码以绘制指定项

	CDC* pDC = CDC::FromHandle(lpDrawItemStruct -> hDC);
	CRect rect;
	GetClientRect(rect);
	DrawButton(pDC, &rect, lpDrawItemStruct -> itemState);

}


void CMybutton::DrawButton(CDC * pDC, CRect * pRect, UINT state)
{
	// 创建内存设备
	HRGN hBaseRgn = CreateRectRgn(0, 0, 0, 0);
	HBRUSH hBrush;
	COLORREF ltInner;	//左上内存边框的颜色
	ltInner = RGB(255,0,0);

	COLORREF rbOuter;	//右下外侧边框的颜色
	rbOuter = RGB(0,255,0);

	HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
	GetWindowRgn(hRgn);

	CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY);
	OffsetRgn(hBaseRgn, 1, 1);
	CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF);//得到左上框的部分并上色为红色
	hBrush = CreateSolidBrush(ltInner);
	FillRgn(*pDC, hBaseRgn, hBrush);
	DeleteObject(hBrush);

	CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY);
	OffsetRgn(hBaseRgn, -1, -1);
	CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF);//得到右上框的部分并上色为红色
	hBrush = CreateSolidBrush(rbOuter);
	FillRgn(*pDC, hBaseRgn, hBrush);
	DeleteObject(hBrush);

}
最后,我们在派生类的OnCreate函数中,设置区域:
int CMybutton::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CButton::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您专用的创建代码
	SetWindowRgn(m_hRgn,true);

	return 0;
}
下面,我们在主对话框类中,调用我们的派生类:
首先定义派生类的对象:
CMybutton m_Open;
同时引入派生类的头文件:
#include "Mybutton.h"
然后在OnInitDialog函数中:
        HRGN c,r;
	c = CreateRectRgn(8, 0, 55, 31);
	r = CreateEllipticRgn(48, 8, 15 + 48, 15 + 8);
	CombineRgn(c, c, r, RGN_OR);
	m_Open.Create(L"Open", WS_CHILD | WS_VISIBLE, CPoint(37, 115), c, this, 101012); 
	DeleteObject(c);
	DeleteObject(r);
在这里,我需要重复强调一个事:对于内存设备对象,我们需要用完之后释放,同时最好还要初始化,还有就是指针对象,一定要记得初始化。要不然,你就会被内存访问问题缠死.....
最后看看实现:

对于按钮标题为什么没有显现,主要是,我并没有设计按钮的前景色,使得自定义按钮的标题颜色是白色,你看不出来,因此,这个按钮自定义类,我还得继续完善......