自绘实现半透明水晶按钮 -- 源码分享

邓学彬 2013-01-04 03:33:08
加精
运行效果


实现方法
1.给按钮加上BS_OWNERDRAW样式
2.重载DrawItem函数,在这里绘制按钮
3.关键之处就是把父窗口的背景复制到按钮上,实现视觉上的透明
4.最后通过AlphaBlend实现半透明.

源码下载:
http://blog.csdn.net/cometnet/article/details/8464693

实现源码
// MyButton.h
#pragma once


// CMyButton

class CMyButton : public CButton
{
DECLARE_DYNAMIC(CMyButton)

public:
CMyButton();
virtual ~CMyButton();
public:
void SetBkColor(COLORREF color);
void SetTextColor(COLORREF color);
private:
bool m_bOver;
bool m_bDown;
bool m_bDisable;
bool m_bTracking;
COLORREF m_bkColor;
COLORREF m_textColor;
protected:
DECLARE_MESSAGE_MAP()
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual void PreSubclassWindow();
public:
virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam);
afx_msg void OnEnable(BOOL bEnable);
private:
void ButtonInit();
void DrawButton();
void DrawButton(HDC hDestDC);
};

// MyButton.cpp : 实现文件
//

#include "stdafx.h"
#include "AlphaButton.h"
#include "MyButton.h"
#include "MainDlg.h"

// CMyButton

IMPLEMENT_DYNAMIC(CMyButton, CButton)

CMyButton::CMyButton()
{
m_bkColor=0xFFFFFF;
m_textColor=0x000000;
}

CMyButton::~CMyButton()
{
}


BEGIN_MESSAGE_MAP(CMyButton, CButton)
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)
ON_WM_ENABLE()
END_MESSAGE_MAP()



// CMyButton 消息处理程序

void CMyButton::SetBkColor(COLORREF color)
{
m_bkColor=color;
}
void CMyButton::SetTextColor(COLORREF color)
{
m_textColor=color;
}

BOOL CMyButton::PreCreateWindow(CREATESTRUCT& cs)
{
BOOL bRet=CButton::PreCreateWindow(cs);
ButtonInit();
return bRet;
}

void CMyButton::PreSubclassWindow()
{
CButton::PreSubclassWindow();
ButtonInit();
}
void CMyButton::ButtonInit()
{
m_bTracking=false;
m_bOver=m_bDown=m_bDisable=false;
m_bDisable=IsWindowEnabled()?FALSE:TRUE;
ModifyStyle(NULL,BS_OWNERDRAW);
}

void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

DrawButton(lpDrawItemStruct->hDC);
}

void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bTracking)
{
m_bOver = TRUE;
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE | TME_HOVER;
tme.dwHoverTime = 50;
m_bTracking = (bool)_TrackMouseEvent(&tme);
}

CButton::OnMouseMove(nFlags, point);
}

void CMyButton::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bDown=TRUE;

CButton::OnLButtonDown(nFlags, point);
}

void CMyButton::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bDown=FALSE;
CButton::OnLButtonUp(nFlags, point);
}
LRESULT CMyButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
m_bOver = FALSE;
m_bTracking = FALSE;
m_bDown=FALSE;
InvalidateRect(NULL, FALSE);
return 0;
}

LRESULT CMyButton::OnMouseHover(WPARAM wParam, LPARAM lParam)
{
m_bOver = TRUE;
InvalidateRect(NULL);
return 0;
}
void CMyButton::DrawButton()
{
HDC hDC=::GetDC(m_hWnd);
DrawButton(hDC);
::ReleaseDC(m_hWnd,hDC);
}
void CMyButton::DrawButton(HDC hDestDC)
{
CRect rc;
GetClientRect(rc);
int nWindth=rc.Width();
int nHeight=rc.Height();
HDC hDC=CreateCompatibleDC(hDestDC);//创建兼容DC,采用双缓冲画出
HDC hMaskDC=CreateCompatibleDC(hDestDC);
HBITMAP hBitmap=CreateCompatibleBitmap(hDestDC,nWindth,nHeight);
HBITMAP hMaskBitmap=CreateCompatibleBitmap(hDestDC,nWindth,nHeight);
HBITMAP hOldBitmap=(HBITMAP)SelectObject(hDC,hBitmap);
HBITMAP hOldMaskBitmap=(HBITMAP)SelectObject(hMaskDC,hMaskBitmap);
SetBkMode(hDC,TRANSPARENT);

//把父窗口的背景图复制到按钮的DC上,实现视觉透明----------------
CMainDlg* pParent=(CMainDlg*)GetParent();
CPoint pt(0,0);
MapWindowPoints(pParent,&pt,1);
pParent->m_bkImage.BitBlt(hDC,rc,pt,SRCCOPY);


//-------------------------------------------------------------
int nAlpha=100;//0--255
int nOffset=0;

HBRUSH hbr=CreateSolidBrush(m_bkColor);
FillRect(hMaskDC,&rc,hbr);
DeleteObject(hbr);

if(m_bDisable){
nAlpha=100;
}else if(m_bDown){
nAlpha=180;
nOffset=1;
}else if(m_bOver){
nAlpha=150;
}else{
nAlpha=100;
}
BLENDFUNCTION blend;
memset( &blend, 0, sizeof( blend) );
blend.BlendOp= AC_SRC_OVER;
blend.SourceConstantAlpha= nAlpha; // 透明度 最大255

HRGN hRgn=CreateRoundRectRgn(0,0,nWindth,nHeight,3,3);
SelectClipRgn (hDC,hRgn);
AlphaBlend (hDC,0,0,nWindth,nHeight,hMaskDC, 0,0,nWindth,nHeight,blend);

CString strText;
GetWindowText(strText);
if(strText!=_T("")){
rc.InflateRect(-2,-2);
rc.OffsetRect(nOffset,nOffset);
HFONT hFont=(HFONT)SendMessage(WM_GETFONT);
if(!hFont)hFont=(HFONT)GetStockObject(DEFAULT_GUI_FONT);
HFONT hOldFont=(HFONT)SelectObject(hDC,hFont);
::SetTextColor(hDC,m_textColor);
::DrawText(hDC,strText,-1,&rc,DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_WORD_ELLIPSIS);
::SelectObject(hDC,hOldFont);
}
SelectClipRgn (hDC,NULL);
DeleteObject(hRgn);
//复制到控件的DC上------------------------
BitBlt(hDestDC,0,0,nWindth,nHeight,hDC,0,0,SRCCOPY);
//删除资源,释放内存-----------------------
SelectObject(hDC,hOldBitmap);
DeleteObject(hBitmap);
DeleteDC(hDC);
SelectObject(hMaskDC,hOldMaskBitmap);
DeleteObject(hMaskBitmap);
DeleteDC(hMaskDC);

}
void CMyButton::OnEnable(BOOL bEnable)
{
CButton::OnEnable(bEnable);
m_bDisable=IsWindowEnabled()?FALSE:TRUE;
DrawButton();
}


源码下载:http://blog.csdn.net/cometnet/article/details/8464693
相关文章:自绘按钮实现颜色选择器
...全文
13906 105 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
105 条回复
切换为时间正序
请发表友善的回复…
发表回复
jianghandaxue 2014-11-25
  • 打赏
  • 举报
回复
搜藏 学习下.............
我喝多了 2014-07-27
  • 打赏
  • 举报
回复
很好,很强大,学了
shuzhongxunyu 2014-03-19
  • 打赏
  • 举报
回复
感谢楼主的分享啊
云满笔记 2014-03-18
  • 打赏
  • 举报
回复
楼主威武!!
VisualUI 2013-05-16
  • 打赏
  • 举报
回复
引用 84 楼 proteus2 的回复:
取消_TrackMouseEvent发送消息的情况:点击该按钮时,整个按钮所在的视图切换到别的视图(通过SwitchToView实现,具体的实现见http://www.codeproject.com/Articles/178/Switching-to-other-views-in-a-doc-view-application) 这时,这些按钮就会出现objcore.cpp line 40 的断言错误,可以通过取消_TrackMouseEvent发送消息实现。
这个还是没怎么弄明白
绿苹果果 2013-05-07
  • 打赏
  • 举报
回复
太有用啦 顶一个
luckydone 2013-04-07
  • 打赏
  • 举报
回复
实用小技巧,谢谢分享
jc5566 2013-03-24
  • 打赏
  • 举报
回复
sololie 2013-03-23
  • 打赏
  • 举报
回复
撸过接分
Daisy__Ben 2013-03-22
  • 打赏
  • 举报
回复
LZ不错哦~ 非常棒的参考 收藏了
信阳毛尖 2013-03-22
  • 打赏
  • 举报
回复
OtakuCode 2013-03-22
  • 打赏
  • 举报
回复
引用 84 楼 proteus2 的回复:
取消_TrackMouseEvent发送消息的情况:点击该按钮时,整个按钮所在的视图切换到别的视图(通过SwitchToView实现,具体的实现见http://www.codeproject.com/Articles/178/Switching-to-other-views-in-a-doc-view-application) 这时,这些按钮就会出现objcore.……
学习了
幸福官 2013-02-26
  • 打赏
  • 举报
回复
谢谢分享,支持一下
音乐男 2013-02-26
  • 打赏
  • 举报
回复
效果看着还不错,很好
SKINSE界面库 2013-02-26
  • 打赏
  • 举报
回复
强大!!!!
  • 打赏
  • 举报
回复
接分,并且接知识。。
LIULIVERYOK 2013-02-23
  • 打赏
  • 举报
回复
zhouganghao 2013-02-21
  • 打赏
  • 举报
回复
学习了!!!!!
proteus2 2013-02-08
  • 打赏
  • 举报
回复
取消_TrackMouseEvent发送消息的情况:点击该按钮时,整个按钮所在的视图切换到别的视图(通过SwitchToView实现,具体的实现见http://www.codeproject.com/Articles/178/Switching-to-other-views-in-a-doc-view-application) 这时,这些按钮就会出现objcore.cpp line 40 的断言错误,可以通过取消_TrackMouseEvent发送消息实现。
proteus2 2013-02-08
  • 打赏
  • 举报
回复
感谢分享. 对于自定义/自绘按钮问题,本人找了很多如CButtonSt、FOOButton这些挺好用,但开发者有的说要收费,挺讨厌的。 还有一点,这些按钮(版主的也一样)在使用的过程中,都存在一个问题_TrackMouseEvent函数发送消息的问题。一般使用不会碰到,但特殊情况下,该问题导致objcore.cpp line 40 的错误,非常讨厌,本人弄了好多天,终于搞定了该问题,即某些情况下,需要取消TrackMouseEvent发送的消息。
加载更多回复(74)

15,980

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧