最近在做客户端程序,遇到了各种透明的问题,下面就自己学到的一点东西写出来,同时希望有更好的方法的可以提出来,大家一起学习!!
一、按钮透明(CButton)
方法一、可以利用首先CImage来保存窗口的背景,再将它绘制到button上,这样可以实现背景透明。不过CImage是ATL里面的类,所以使用CImage就要编译器有ATL并且要会用ATL。下面具体讲解下使用的方法:
1、在窗口中定义CImage对象m_bkImage,并将位图加载到里面,然后设置成窗口背景;
主窗口.h文件中定义
public:
CImage m_bkImage;
主窗口.cpp文件中加载和设置窗口背景
BOOL CMainDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
m_bkImage.LoadFromResource(AfxGetInstanceHandle(),IDB_BITMAP1);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
BOOL CMainDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rc;
GetClientRect(&rc);
m_bkImage.BitBlt(pDC->GetSafeHdc(),rc,CPoint(0,0),SRCCOPY);
return TRUE;
}
2、在绘制(DrawItem)button时,把窗口对应的图像BitBlt到button上
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);
}
上面的代码其实是制作水晶按钮的代码,不过大家可以看到其中有一段代码是专门用来赋值背景的;
这种方法的实例大家可以看看这个:http://blog.youkuaiyun.com/cometnet/article/details/8464693
方法二、在OnEraseBkgnd把系统的绘制去掉,然后他就变成透明的了
1、这种方法很简单,要实现最直接的办法就是把这个函数体内的所用代码去掉,然后返回真就可以了
BOOL CBmpButton::OnEraseBkgnd(CDC* pDC)
{
//去掉系统自绘背景,是背景透明
return true;
}
这种方法虽然直接,但他只是是背景透明如果你在背景上画了东西,下次也不会擦除。所以我们应该在绘制前,把主窗口按钮对应位置的图像拷贝到这里来:
BOOL CMyBuuton::OnEraseBkgnd(CDC* pDC)
{
CWnd *pParent = GetParent();
CRect rc;
GetWindowRect(rc);
pParent->ScreenToClient(rc);
pParent->InvalidateRect(rc,false);
pParent->UpdateWindow();
CDC *dcParent = pParent->GetDC();
pDC->BitBlt(0,0,rc.Width(),rc.Height(),dcParent,rc.left,rc.top,SRCCOPY);
pParent->ReleaseDC(dcParent);
return true;
}
这种方法的画感觉有点闪烁,我自己还没有找到方法,大家有解决的可以分享呀