绘制半透明按钮——基础篇

写在前面的话:

我能够做出半透明按钮,得感谢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);
}

你可能感兴趣的:(绘制半透明按钮——基础篇)