MFC中如何给CButton添加不同状态位图 您所在的位置:网站首页 mfc代码创建按钮 MFC中如何给CButton添加不同状态位图

MFC中如何给CButton添加不同状态位图

2023-01-12 05:08| 来源: 网络整理| 查看: 265

文章目录 前言 一、环境 二、步骤 1 、创建MFC工程 2、从CButton中派生一个类 3、关于CMyButton类的必要说明 4、在对话框类中使用CMyButton 总结

前言

如何给MFC中CButton按钮添加位图,分别在正常、单击、停留、获得焦点四种状态时显示不同位图,可以采用从CButton类派生一个新类的方式来实现。 网上有一些其他的类似的实现方式,本文重点参考了这篇文章,并做了一些修改。 https://blog.csdn.net/chen1083376511/article/details/73321840

一、环境

vs2008+Win10

二、步骤 1 、创建MFC工程 创建基于对话框的MFC工程,名称取为BitmapButton。 在对话框资源编辑器中拖入一个CButton按钮,修改ID号,Owner Draw属性修改为True,这样,这个按钮就成为了自绘控件(具有风格BS_OWNERDRAW)。一个自绘控件的外观发生变化时,MFC框架会调用DrawItem函数. 准备四张位图,分别显示按钮的四种状态,添加至工程的资源中,正常、按下、获取焦点、停留状态ID号分别改为IDB_BMP_NORMAL、IDB_BMP_PRESS、IDB_BMP_HOVER、IDB_BMP_FOCUS。 2、从CButton中派生一个类

取名为CMyButton,并为这个类添加OnMouseMove、OnMouseLeave、OnMouseHover响应函数,重写DrawItem函数。详细可见下面代码

//MyButton.h #pragma once #include "afxwin.h" class CMyButton : public CButton { public: CMyButton(UINT idBmpNormal,UINT idBmpPress,UINT idBmpHover,UINT idBmpFocus); ~CMyButton(void); void SetBmpId(UINT idBmpNormal,UINT idBmpPress,UINT idBmpHover,UINT idBmpFocus); protected: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); afx_msg void OnMouseHover(UINT nFlags, CPoint point); DECLARE_MESSAGE_MAP() private: CBitmap m_bmpNormal; //正常状态位图 CBitmap m_bmpPress; //按下位图 CBitmap m_bmpHover; //鼠标悬停位图 CBitmap m_bmpFocus; //获取焦点位图 bool m_bTrackMouseEvent; //是否跟踪鼠标状态 bool m_bHover; //鼠标是否悬停上方 };

实现文件为:

#include "StdAfx.h" #include "MyButton.h" CMyButton::CMyButton(UINT idBmpNormal,UINT idBmpPress,UINT idBmpHover,UINT idBmpFocus) :m_bTrackMouseEvent(true) ,m_bHover(false) { m_bmpNormal.LoadBitmap(idBmpNormal); m_bmpPress.LoadBitmap(idBmpPress); m_bmpHover.LoadBitmap(idBmpHover); m_bmpFocus.LoadBitmap(idBmpFocus); } CMyButton::~CMyButton(void) { } void CMyButton::SetBmpId(UINT idBmpNormal,UINT idBmpPress,UINT idBmpHover,UINT idBmpFocus) { //此处注意,CBitmap多次加载位图,程序会报错 if(m_bmpNormal.m_hObject) m_bmpNormal.DeleteObject(); if(m_bmpPress.m_hObject) m_bmpPress.DeleteObject(); if(m_bmpFocus.m_hObject) m_bmpFocus.DeleteObject(); if(m_bmpHover.m_hObject) m_bmpHover.DeleteObject(); m_bmpNormal.LoadBitmap(idBmpNormal); m_bmpPress.LoadBitmap(idBmpPress); m_bmpFocus.LoadBitmap(idBmpFocus); m_bmpHover.LoadBitmap(idBmpHover); } BEGIN_MESSAGE_MAP(CMyButton, CButton) ON_WM_MOUSEMOVE() ON_WM_MOUSELEAVE() ON_WM_MOUSEHOVER() END_MESSAGE_MAP() void CMyButton::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if(m_bTrackMouseEvent) { TRACKMOUSEEVENT cTrackEvent; cTrackEvent.cbSize=sizeof(TRACKMOUSEEVENT); cTrackEvent.dwFlags=TME_HOVER|TME_LEAVE; cTrackEvent.dwHoverTime=10; //鼠标停留多久触发悬停消息 cTrackEvent.hwndTrack=GetSafeHwnd(); if(::_TrackMouseEvent(&cTrackEvent)) //如果调用失败,不再跟踪鼠标事件 m_bTrackMouseEvent=false; } CButton::OnMouseMove(nFlags, point); } void CMyButton::OnMouseLeave() { m_bHover=false; m_bTrackMouseEvent=true; //重新开始跟踪 Invalidate(); //重绘按钮 CButton::OnMouseLeave(); } void CMyButton::OnMouseHover(UINT nFlags, CPoint point) { m_bTrackMouseEvent=false; //不再跟踪,因为已经在控件范围内了 m_bHover=true; Invalidate(); //重绘按钮 CButton::OnMouseHover(nFlags, point); } void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CRect rect=lpDrawItemStruct->rcItem; CDC* pDc=CDC::FromHandle(lpDrawItemStruct->hDC); int nSaveDc=pDc->SaveDC(); CBitmap* pBmp=NULL; if(lpDrawItemStruct->itemState & ODS_SELECTED) //选中 { pBmp=&m_bmpPress; } else if(lpDrawItemStruct->itemState & ODS_FOCUS) //焦点 { pBmp=&m_bmpFocus; } else if(m_bHover) //停留 { pBmp=&m_bmpHover; } else //正常 pBmp=&m_bmpNormal; BITMAP bmp; pBmp->GetBitmap(&bmp); CDC dcCompatible; dcCompatible.CreateCompatibleDC(pDc); dcCompatible.SelectObject(pBmp); pDc->StretchBlt(0,0,rect.Width(),rect.Height(), &dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); pDc->RestoreDC(nSaveDc); } 3、关于CMyButton类的必要说明 _TrackMouseEven函数:当鼠标离开特定窗口时,这个函数会发出WM_MOUSELEAVE;当鼠标悬停在窗口时,这个函数会发出WM_MOUSEHOVER消息,至于悬停多久会发消息,取决于TRACKMOUSEEVENT结构中的dwHoverTime值。 OnMouseMove响应函数:注意在该函数中,首先检查成员变量m_bTrackMouseEvent是否为真,然后再调用_TrackMouseEvent函数。 OnMouseHover响应函数:注意在该函数中,将m_bTrackMouseEvent赋值为false,这是因为此时鼠标已经在控件范围内了,没有必要再执行_TrackMouseEvent函数。这里有个问题,为什么不再跟踪鼠标事件,却可以收到鼠标离开的事件,这是因为:只要调用一次_TrackMouseEvent函数,只有等到WM_MOUSELEAVE消息产生时,所有跟踪请求才会结束。 通过在OnMouseHover、OnMouseLeave调用Invalidate(),使框架能够调用DrawItem。 4、在对话框类中使用CMyButton

在对话框类中新增成员变量m_wndBtn,并让它和CButton按钮相关联。

// BitmapButtonDlg.h : 头文件 // #pragma once #include "afxwin.h" #include "MyButton.h" // CBitmapButtonDlg 对话框 class CBitmapButtonDlg : public CDialog { public: CBitmapButtonDlg(CWnd* pParent = NULL); // 标准构造函数 enum { IDD = IDD_BITMAPBUTTON_DIALOG }; protected: HICON m_hIcon; virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() private: CMyButton m_wndBtn; //可以实现位图切换的按钮 };

然后,在构造函数中初始化这个CMyButton类型的按钮

CBitmapButtonDlg::CBitmapButtonDlg(CWnd* pParent /*=NULL*/) : CDialog(CBitmapButtonDlg::IDD, pParent) ,m_wndBtn(IDB_BMP_NORMAL,IDB_BMP_PRESS,IDB_BMP_HOVER,IDB_BMP_FOCUS) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); }

实际上,CMyButton的SetBmpId接口也可以使程序在其他时候更换显示的四张位图,本实例暂未使用。

总结

在以上类的基础上,可以扩展CButton的更多自定义功能。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有