准备制作自己的控件类,按钮是第一个,我会将我在其中遇到困难和大家分享一些,只要实现下面的功能,按钮类就可以满足大部分的需求
按钮类功能:
1、正常
这个状态可以设置为光离开按钮,需要添加变量,然后在OnMouseLeave中获取状态
2、光标在按钮区域上
光标在按钮上OnMouseMove和OnMouseHover
3、按下
4、当前按钮为活动按钮
5、按钮不可用
6、位图按钮上显示名称
7、制作圆角矩形、圆形按钮
其中前三个都很好实现,下面是响应函数;
OnMouseLeave()//光标离开按钮区域
OnMouseHover()//光标在按钮区域
OnLButtonDown//按下
OnLButtonUp//松开
//以下4个问题都是在DrawItem(DRAWITEMSTRUCT lpdrawitemstruct)中添加代码
第四个问题的解决方式:
函数:DrawItem(DRAWITEMSTRUCT lpdrawitemstruct)
lpdrawitemstruct->itemState();//itemState:指定了当前绘制操作完成后,所绘项的可见状态。例如,如果菜单项应该被灰色显示,则可以指定ODS_GRAYED状态标志。其取值可以为下表中所示值的一个或者多个的联合。
【ODS_FOCUS=H8:如果菜单项将被选中,则可设置该值。该值只对菜单项有用。】
所以只要通过判断lpdrawitemstruct->itemState();是否等于ODS_FOCUS=H8:就可以设置按钮为当前活动按钮时的响应了。
第五个问题
函数:DrawItem(DRAWITEMSTRUCT lpdrawitemstruct)
lpdrawitemstruct->itemState();//itemState:指定了当前绘制操作完成后,所绘项的可见状态。例如,如果菜单项应该被灰色显示,则可以指定ODS_GRAYED状态标志。其取值可以为下表中所示值的一个或者多个的联合。
【ODS_DISABLED=H4:如果控件将被禁止,则设置该值。】
所以只要通过判断lpdrawitemstruct->itemState();是否等于ODS_DISABLED=H4:就可以设置按钮为不可用按钮时的响应了。
第六个问题:按钮上的名称怎么显示(我的按钮的几个状态都是位图切换)
CString add;
CDC ButtonDC;
ButtonDC.Attach(lpdrawitemstruct->hDC);//获取DC
ButtonDC.SetBkMode(TRANSPARENT);//字体背景透明
GetWindowText(add);
.DrawText(add,CRect(5,5,10,10),DT_CENTER | DT_VCENTER | DT_SINGLELINE);
第七个问题:怎么制作圆形按钮或者是圆角按钮
CRng rc;
rc.CreateRoundRect(0,0,rect.Width(),rect.Heignt(),50,50);//获取一个圆角矩形区域
::GetWindowRgn(lpdrawitemstruct->hwndItem,rc);
ButtonDC.SelectClipRng(&rc);
SetWindowRgn(rc,true)//有效区域
最后记得释放内存
ButtonDC.DeleteDC();
2019-07-25
按钮一共设置四个状态,正常、光标在上面、按钮按下、不可用
函数:DrawItem(DRAWITEMSTRUCT lpdrawitemstruct)中
1、if (lpDrawItemStruct->itemState & ODS_SELECTED)//为按钮的按下
2、if (state&ODS_DISABLED)//按钮被禁用的状态
正常状态和光标在按钮上面的状态需要用到
在头文件添加一个move_button的变量
//添加自绘功能
void MyButton::PreSubclassWindow()
{
ModifyStyle(0, BS_OWNERDRAW);
CButton::PreSubclassWindow();
}
//
void MyButton::OnMouseMove(UINT nFlags, CPoint point)
{
//添加才能响应OnMouseLeave和OnMouseHover函数
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER | TME_LEAVE;
tme.dwHoverTime = HOVER_DEFAULT;
tme.hwndTrack = m_hWnd;
_TrackMouseEvent(&tme);
//刷新才能响应DrawItem函数
if (!move_button)
Invalidate();
//这个状态添加在move中是因为在这里响应的速度比OnMouseHover要快
move_button = true;
CButton::OnMouseMove(nFlags, point);
}
//光标离开
void MyButton::OnMouseLeave()
{
//状态改变就调用DrawItem
if (move_button)
Invalidate();
move_button = false;
CButton::OnMouseLeave();
}
//光标在按钮上
void MyButton::OnMouseHover(UINT nFlags, CPoint point)
{
/*if (!move_button)
Invalidate();
move_button = true;*/
CButton::OnMouseHover(nFlags, point);
}
//在切换位图的时候按钮背景会闪烁,添加后就没有这个问题了
BOOL MyButton::OnEraseBkgnd(CDC* pDC)
{
return true;
//return CButton::OnEraseBkgnd(pDC);
}
3、if (move_button == true)//光标移动到上面
4、if (move_button == false)//正常按钮
当获取完这些状态后在其中使用
if (lpDrawItemStruct->CtlID == IDC_BUTTON1)//判断当前状态是那个按钮
例子:在DrawItem中添加
CDC ButtonDC;
CBitmap bitmapTrans;
BITMAP bmp;
CDC mem;
CRect rc;
//得到用于绘制按钮的DC
ButtonDC.Attach(lpDrawItemStruct->hDC);
ButtonDC.SetBkMode(TRANSPARENT);
//准备用于向按钮区域传输位图
mem.CreateCompatibleDC(&ButtonDC);
//获取按钮所占的矩形大小
rc = lpDrawItemStruct->rcItem;
//获取按钮目前所处的状态,根据不同的状态绘制不同的按钮
int state = lpDrawItemStruct->itemState;
//如果按钮已经得到焦点,绘制选中状态下的按钮
//if (state&ODS_FOCUS)//选中
if (lpDrawItemStruct->itemState & ODS_SELECTED)//按下
{
if (lpDrawItemStruct->CtlID == IDC_BUTTON12)//官网
bitmapTrans.LoadBitmap(IDB_BITMAP1);
//按钮多久继续添加按钮判断
bitmapTrans.GetBitmap(&bmp);
CBitmap *old = mem.SelectObject(&bitmapTrans);
//向按钮所在位置传输位图
//使用StretcnBlt的目的是为了让位图随按钮的大小而改变
ButtonDC.StretchBlt(rc.left, rc.top, rc.right, rc.bottom, &mem, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
mem.SelectObject(old);
}
else if(move_button)//光标在按钮上
{
if (lpDrawItemStruct->CtlID == IDC_BUTTON12)//官网
bitmapTrans.LoadBitmap(IDB_BITMAP2);
//按钮多久继续添加按钮判断
bitmapTrans.GetBitmap(&bmp);
CBitmap *old = mem.SelectObject(&bitmapTrans);
//向按钮所在位置传输位图
//使用StretcnBlt的目的是为了让位图随按钮的大小而改变
ButtonDC.StretchBlt(rc.left, rc.top, rc.right, rc.bottom, &mem, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
mem.SelectObject(old);
}
else.....等等
//设置文字背景为透明
ButtonDC.SetBkMode(TRANSPARENT);
bitmapTrans.DeleteObject();
mem.DeleteDC();
ButtonDC.DeleteDC();