写在前面的话:
我能够做出半透明按钮,得感谢CSDN上很多人的帮助,给我耐心的指点,让我一点点的完成半透明按钮,所以我想把这个分享出来,虽然不是很难的技术,但是也许可以给需要的人一点点小的指导。
1.绘制半透明按钮的思路:
所谓的“透明”其实不是真的“透明”,而是子控件的背景和父窗口的背景一样,从而造成“透明”的视觉效果。所以绘制半透明的按钮的思路是:
创建三个内存DC(当然,还必须创建三个位图,2个大小为按钮客户区域的大小,1个大小为父窗口客户区的大小)
内存DC1中的位图是父窗口的背景
内存DC2中的位图是DC1中对应按钮区域的那部分
内存DC3中的位图是纯色的,不管你用什么方法,反正把整个位图填充成一种颜色就行
然后把 内存DC3 AlphaBlend 到 内存DC2
最后把 内存DC2 BitBlt 到屏幕DC
2.如何获取父窗口的背景
由于父窗口背景是加载的一张bmp图像,所以我们可以把加载图像的过程放在父窗口的OnEraseBkgnd(CDC* pDC)
中响应。为什么要放在OnEraseBkgnd(CDC* pDC)
中呢?
这样我们可以在子控件中向父窗口发送SendMessage(WM_ERASEBKGND, (
WPARAM
)dcMem.m_hDC,0)消息来获取父窗口的背景
3.实现代码,依然是自己写个button类来继承CButton
button按钮自绘code
// MyButton.h :header file
#pragma once
#ifndef _H_MYBUTTON_H
#define _H_MYBUTTON_H
class CMyButton : public CButton
{
DECLARE_DYNAMIC(CMyButton)
public:
CMyButton();
~CMyButton();
virtual void PreSubclassWindow();
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void DrawAlphaButton(CDC *pDC);
protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
public:
bool isbuttondown;//按钮是否被按下
};
#endif
// MyButton.cpp : implementation file
//
#include "MyButton.h"
#include "AlphaButtonDlg.h"
IMPLEMENT_DYNAMIC(CMyButton, CButton)
CMyButton::CMyButton()
{
isbuttondown=false;
}
CMyButton::~CMyButton()
{
}
BEGIN_MESSAGE_MAP(CMyButton, CButton)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
void CMyButton::PreSubclassWindow()
{
this->ModifyStyle(0, BS_OWNERDRAW); //修改为自绘button
CButton::PreSubclassWindow();
}
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
HDC hdc=lpDrawItemStruct->hDC;
CDC *pDC=CDC::FromHandle(hdc);
DrawAlphaButton(pDC);
}
void CMyButton::OnLButtonDown(UINT nFlags, CPoint point)
{
isbuttondown=true;
Invalidate(false);
}
void CMyButton::OnLButtonUp(UINT nFlags, CPoint point)
{
isbuttondown=false;
Invalidate(false);
}
void CMyButton::DrawAlphaButton(CDC *pDC)
{
CRect rect;
CRect winrect;
CRect parantrect;
GetParent()->GetClientRect(¶ntrect);
GetClientRect(&rect);
//获取button控件相对于父窗口的坐标位置
GetWindowRect(&winrect);
GetParent()->ScreenToClient(&winrect);
CDC dcMem; //内存DC中的位图是父窗口背景中对应按钮的那部分
CDC dcMem2;//内存DC中的位图是春色的
CDC dcMem3;//内存DC中的位图是父窗口的背景
dcMem.CreateCompatibleDC(pDC);
dcMem2.CreateCompatibleDC(pDC);
dcMem3.CreateCompatibleDC(pDC);
CBitmap bkimg; //内存中承载临时图象的位图
CBitmap bkimg2;
CBitmap bkimg3;
bkimg.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
bkimg2.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
bkimg3.CreateCompatibleBitmap(pDC, parantrect.Width(), parantrect.Height());
CBitmap *pImgOld=dcMem.SelectObject(&bkimg);
CBitmap *pImgOld2=dcMem2.SelectObject(&bkimg2);
CBitmap *pImgOld3=dcMem3.SelectObject(&bkimg3);
//绘制纯色位图
HBRUSH hbr=CreateSolidBrush(RGB(255,0,0));
FillRect(dcMem2,&rect,hbr);
DeleteObject(hbr);
//设置剪裁区(不设置也可以,设置了貌似可以减少绘制的面积,提高点点速度吧)
HRGN hRgn=CreateRectRgn(winrect.left, winrect.top,winrect.right,winrect.bottom);
SelectClipRgn (dcMem3.m_hDC,hRgn);
//获取父窗口的背景
GetParent()->SendMessage( WM_ERASEBKGND, (WPARAM)dcMem3.m_hDC, 0);
//获取父窗口中对应按钮的那部分背景
dcMem.BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem3, winrect.left, winrect.top, SRCCOPY);
BLENDFUNCTION blend;
memset( &blend, 0, sizeof( blend) );
blend.BlendOp= AC_SRC_OVER;
blend.SourceConstantAlpha= 150; // 透明度 最大255
//AlphaBlend 得到半透明背景
AlphaBlend (dcMem.m_hDC,0,0,rect.Width(), rect.Height(),dcMem2.m_hDC, 0,0,rect.Width(), rect.Height(),blend);
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, SRCCOPY);
CString strText;
GetWindowText(strText);
SetBkMode(pDC->m_hDC,TRANSPARENT);
//按钮按下后字体向下偏移
if (isbuttondown)
{
CRect rectdown=rect;
rectdown.OffsetRect(0,1);
DrawText(pDC->m_hDC,strText,-1,&rectdown,DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_WORD_ELLIPSIS);
}
else
{
DrawText(pDC->m_hDC,strText,-1,&rect,DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_WORD_ELLIPSIS);
}
dcMem.DeleteDC();
dcMem2.DeleteDC();
dcMem3.DeleteDC();
bkimg.DeleteObject();
bkimg2.DeleteObject();
bkimg3.DeleteObject();
ReleaseDC(pDC);
}
父窗口对话框的实现code
// AlphaButtonDlg.h : header file
//
#pragma once
#include "MyButton.h"
#include "resource.h"
// CAlphaButtonDlg dialog
class CAlphaButtonDlg : public CDialogEx
{
// Construction
public:
CAlphaButtonDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
enum { IDD = IDD_ALPHABUTTON_DIALOG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CMyButton mybtn1;
CMyButton mybtn2;
CMyButton mybtn3;
CBitmap bkimg;
public:
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnWindowPosChanging(WINDOWPOS* lpwndpos);
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
afx_msg void OnBnClickedBn3();
};
// AlphaButtonDlg.cpp : implementation file
//
#include "AlphaButton.h"
#include "AlphaButtonDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAlphaButtonDlg dialog
CAlphaButtonDlg::CAlphaButtonDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CAlphaButtonDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
bkimg.LoadBitmap(IDB_BITMAP1);
}
void CAlphaButtonDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX,IDC_BN_1,mybtn1);
DDX_Control(pDX,IDC_BN_2,mybtn2);
DDX_Control(pDX,IDC_BN_3,mybtn3);
}
BEGIN_MESSAGE_MAP(CAlphaButtonDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_ERASEBKGND()
ON_WM_WINDOWPOSCHANGING()
ON_WM_CTLCOLOR()
ON_BN_CLICKED(IDC_BN_3, &CAlphaButtonDlg::OnBnClickedBn3)
END_MESSAGE_MAP()
// CAlphaButtonDlg message handlers
BOOL CAlphaButtonDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
void CAlphaButtonDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
CDialogEx::OnSysCommand(nID, lParam);
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CAlphaButtonDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
//LoadBkImage();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAlphaButtonDlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
BOOL CAlphaButtonDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
GetClientRect(rect);
CDC dcMem;
dcMem.CreateCompatibleDC(pDC);
BITMAP bitmap;
bkimg.GetBitmap(&bitmap);
CBitmap *pbmpOld=dcMem.SelectObject(&bkimg);
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);
dcMem.SelectObject(pbmpOld);
dcMem.DeleteDC();
return true;
}
//窗口大小改变时,窗口重绘
void CAlphaButtonDlg::OnWindowPosChanging(WINDOWPOS* lpwndpos)
{
CDialogEx::OnWindowPosChanging(lpwndpos);
if (!(lpwndpos->flags & SWP_NOSIZE))
{
Invalidate(FALSE);
}
}
//重载OnCtlColor是为防止重绘按钮时,发生闪烁现象
HBRUSH CAlphaButtonDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
if (nCtlColor == CTLCOLOR_BTN)
{
pDC->SetBkMode(TRANSPARENT);
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
}