⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vc++button.txt

📁 有一种按键
💻 TXT
字号:
Visual C++实现透明浮动按键

有一种按键,看起来是一幅完整的图片,当鼠标移到按键区域时,图片的一部分凸现,形成一个按键,当鼠标移走时又恢复原来状态。 

首先从CButton派生出一个新类CDrawButton, 把按键的标题显示出来. 这个可以重载CButton类的成员函数DrawItem()来实现.

void CDrawButton::DrawItem
(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
CRect rect=lpDrawItemStruct- >rcItem;//得到按键区域
CString sCaption;
dc.Attach(lpDrawItemStruct- >hDC); //得到设备环境CDC
VERIFY(lpDrawItemStruct- >CtlType==ODT_BUTTON);
GetWindowText(sCaption);//得到按键的标题
dc.SetBkMode(TRANSPARENT);//透明显示
CFont* m_pOldFont=dc.SelectObject(m_pFont);
dc.DrawText(sCaption,&rect,DT_CENTER|DT_VCENTER|DT_SINGLELINE);
dc.SelectObject(m_pOldFont);
}

m_pFont是成员变量,它保存了对话框的字体指针,为了按键的标题风格与对话框的字体风格一致,在初始化时调用对话框的成员函数GetFont()即可得到指向对话框字体的CFont类指针。 

使按键浮动显示, 要通过自绘来表示按键的各种状态,可填写DRAWITEMSTRUCT来通知DrawItem()函数需要做什么,我们先了解一下DRAWITEMSTRUCT: 

typedef struct tagDRAWITEMSTRUCT{
	UINT CtlType; // 控件类型
	UINT CtlID;// 控件的ID号
	UNIT itemID;//菜单项的索引
	UINT itemAction;// 绘图操作
	UINT itemState; // 状态
	HWND hwndItem; // 控件的窗口句柄
	HDC hDC; // 相关的设备环境
	RECT rcItem;//控件的范围
	DWORD itemData;//指定与菜单项相联系的应用程序定义的32位值
}DRAWITEMSTRUCT;

利用这个结构先做一个按键状态设置函数: 
void CDrawButton::SetButtonMode(UINT action, UINT mode)
{
 // TODO: Add your message handler code 
here and/or call default
	DRAWITEMSTRUCT DIS; 
	DIS.CtlType = ODT_BUTTON; 
	DIS.CtlID = GetDlgCtrlID(); 
	DIS.itemAction = action; 
	DIS.itemState = mode; 
	DIS.hwndItem = GetSafeHwnd(); 
	DIS.hDC = GetDC()- >GetSafeHdc(); 
	GetClientRect(&(DIS.rcItem)); 
	SendMessage(WM_DRAWITEM,(WPARAM)
GetSafeHwnd(),(LPARAM)&DIS);
	ReleaseDC(CDC::FromHandle(DIS.hDC));
}

这样,我们可以响应鼠标的各种消息来设置按键的各种状态: 
void CDrawButton::OnMouseMove
(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code 
here and/or call default
	CRect rect;
	GetClientRect(&rect);
	if(rect.PtInRect(point)){
		if (mBtnStats==BTN_NORMAL){
	SetButtonMode(ODA_SELECT, ODS_FOCUS); 
			SetCapture();
		}
	}
	else{
//AutoLoad(GetDlgCtrlID(),GetParent());
SetButtonMode(ODA_DRAWENTIRE,ODS_DEFAULT);
		ReleaseCapture();
	}

	CButton::OnMouseMove(nFlags, point);
}

mBtnStats是个UINT类型的成员变量,它可以有三种自定义状态: 

BTN_NORMAL	正常状态
BTN_UP		鼠标移入按键区域或释放鼠标
BTN_DOWN	按下鼠标

当在按键区域释放鼠标时,必须发送WM_COMMAND消息:
void CDrawButton::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code
 here and/or call default
	CRect rect;
	GetClientRect(&rect);
	if(rect.PtInRect(point)){
		if (mBtnStats==BTN_DOWN)
			GetParent()- >SendMessage(WM_COMMAND,
		MAKELPARAM(GetDlgCtrlID(),BN_CLICKED),
		(LPARAM)GetSafeHwnd());
		SetCapture();
	}
	else{
	SetButtonMode(ODA_DRAWENTIRE,ODS_DEFAULT);
		ReleaseCapture();
	}

	CButton::OnLButtonUp(nFlags, point);
}

接着就是绘制按键的各种状态:由于按键必须“透明”,所以在按下和释放时只在按键区域的四周加上一个3D边框就行了。而在正常状态下,则必须去掉边框恢复背景。但如何恢复背景图象呢?

在按键初始化时,先把被按键覆盖了的区域保存在一个CBitmap类中,以后需要重绘按键时就把这个CBitmap画在按键上就行了。 

void CDrawButton::DrawItem
(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	// TODO: Add your code to draw the specified item
	CDC dc;
	CRect rect=lpDrawItemStruct- >rcItem;
	CString sCaption;
	dc.Attach(lpDrawItemStruct->hDC); //得到绘制的设备环境CDC
	VERIFY(lpDrawItemStruct- >CtlType==ODT_BUTTON);

	if (lpDrawItemStruct- >itemAction & ODA_DRAWENTIRE){
		//重绘控件(正常状态)
		mBtnStats=BTN_NORMAL;
		if (m_pBitmap!=0){
			CDC memDC; 
			memDC.CreateCompatibleDC(&dc);
			memDC.SelectObject(m_pBitmap);
	dc.BitBlt(0, 0, rect.Width(), rect.Height(),
				&memDC, 0, 0, SRCCOPY); 
			memDC.DeleteDC();
		}
		//显示按键标题
		GetWindowText(sCaption);
		dc.SetBkMode(TRANSPARENT);
		if (m_pFont!=0){
		CFont* m_pOldFont=dc.SelectObject(m_pFont);
		dc.DrawText(sCaption,&rect,
	DT_CENTER|DT_VCENTER|DT_SINGLELINE);
			dc.SelectObject(m_pOldFont);
		}
	}

if ((lpDrawItemStruct- >itemState & ODS_SELECTED) &&
 (lpDrawItemStruct- >itemAction & ODA_SELECT)){
//按下鼠标
mBtnStats=BTN_DOWN;
dc.Draw3dRect(&rect,RGB(128,128,128),RGB(192,192,192));
rect.top=rect.top+1;rect.bottom=rect.bottom-1;
rect.left=rect.left+1;rect.right=rect.right-1;
dc.Draw3dRect(&rect,RGB(0,0,0),RGB(255,255,255));
	}

if(!(lpDrawItemStruct- >itemState & ODS_SELECTED) &&
 (lpDrawItemStruct- >itemAction & ODA_SELECT)){
//释放鼠标或鼠标进入按键区域
mBtnStats=BTN_UP;
dc.Draw3dRect(&rect,RGB(255,255,255),RGB(0,0,0));
rect.top=rect.top+1;rect.bottom=rect.bottom-1;
rect.left=rect.left+1;rect.right=rect.right-1;
dc.Draw3dRect(&rect,RGB(192,192,192),RGB(128,128,128));
	}
 
	dc.Detach();
}

接着就必须一些初始化工作,其中最关键就是把被按键覆盖了的区域保存进CBitmap类中,CDC::StretchBlt()函数可以把位图的指定区域从一个设备拷贝到另一个设备中,这样可以很方便地把窗口或对话框的某个区域保存,条件是获得其DC: 
void CDrawButton::LoadBack(CWnd *pParent)
{
	ASSERT(GetStyle() & BS_OWNERDRAW); 
	if (m_pBitmap!=0) return;

	CRect rect;
	GetWindowRect(&rect);
	pParent- >ScreenToClient(&rect);//获得按键区域
	CPaintDC dc(pParent);
	if (m_pBitmap==0) m_pBitmap=new CBitmap;//初始化位图
	m_pBitmap- >CreateCompatibleBitmap 
(&dc,rect.Width(),rect.Height());
	CDC memDC;
	memDC.CreateCompatibleDC(&dc);
	memDC.SelectObject(m_pBitmap);
memDC.StretchBlt(0, 0, rect.Width(),rect.Height(), &dc,
	rect.left, rect.top, 
rect.Width(),rect.Height(), SRCCOPY);//保存
	memDC.DeleteDC();
m_pFont=pParent- >GetFont();//获得窗口或对话框的字体

	ModifyStyle(0,WS_VISIBLE);//显示按键

	SetBitmapMode(ODA_DRAWENTIRE,0);//绘制按键
}

而使这个类和对话框上的按键产生联系还必须调用一下SubclassDlgItem(): 
BOOL CDrawButton::AutoLoad(UINT nID, CWnd *pParent)
{
 // first attach the CDrawButton to the dialog control 

	if (m_pBitmap!=0) return FALSE;

	if (!SubclassDlgItem(nID, pParent)) return FALSE;

	LoadBack(pParent);

	return TRUE;
}

这个类还必须具有三个成员变量: 
	CFont* m_pFont;
	CBitmap* m_pBitmap;
	UINT mBtnStats;

在构造函数中初始化这些变量
	m_pBitmap=0;
	m_pFont=0;
	//赋予0是可以的
	mBtnStats=BTN_NORMAL;

在折构函数中拆除位图
	if(m_pBitmap!=0) delete m_pBitmap;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -