分类: C/C++
2008-04-23 21:49:28
透明窗体的又一实现
作者:
前面拜读过本站无数高手的许多好文章,受益非浅,首先向各位大侠致敬!今天编程偶有小得,不敢独享,特拿出来与各位共享,希望对某些朋友有些许帮助。
透明窗体的问题相信大家已经很熟悉了,前面的几期在线杂志也有几篇详尽的教程,总结一下就是通过SetWindowRgn这个函数来实现,具体的裁切框用CRgn来生成,比较简单的
象圆,椭圆,圆角窗口等CRgn类都提供了相应的生成方法,我们如果想根据自己的图片来生成裁切框前面的朋友提到的方法是首先生成一个矩形裁切框,然后扫描图片,根据象素点的颜色与掩码颜色的匹配与否,对裁切框进行删减(生成一个新的,然后XOR),对于这种方法我就不详细描述了,有需要的朋友请查阅以前的文章,我首先说一下我遇到的不足之处:
如果我的窗体支持Resize,那么我调整大小的过程中,要不停的计算裁切框(要逐点扫描象素,并对裁切框进行操作),计算量相当大,特别当窗体比较大的时候更是如此,会造成窗体的闪烁。
我查阅相关资料得到另一种实现方法,简单实用,那就是利用 SetLayeredWindowAttributes
这个函数,相信许多朋友都见过Microsoft对他的描述但用过的并不多,要用它,要安装最新的SDK,否则会出现没有定义的错误。小弟懒得下载,下面的介绍采用了一般API调用的格式。如果你已经有最新的SDK,那你的程序可以变得更加简练!
首先介绍一下这个函数:
BOOL SetLayeredWindowAttributes( HWND hwnd, // 应用目标窗口的句柄 COLORREF crKey, // 掩码的颜色,可以用RGB(r,g,b)来指定 BYTE bAlpha, // 掩码颜色部分的Alpha值,0是全透明,255是完全不透明 DWORD dwFlags // 透明方式 );要说名的是这个函数只在Windows2000及以上版本才支持。MSDN对要求的描述如下
还有就是这个函数对于有标题框的窗体支持不好,就是它裁切的只是客户区域,好在我们要制作透明窗体的场合一般用不到标题框 下面就说名例程的制作过程。(我旨在说明这种透明窗体的思路及函数的用法,所以代码非常简单,并且没有必要的错误验证机制,希望大家谅解)Windows NT/2000/XP: Included in Windows 2000 and later. Windows 95/98/Me: Unsupported. Header: Declared in Winuser.h; include Windows.h. Library: Use User32.lib.

CBitmap * m_oldBitmap; //指向内存DC原来的 Bitmap CDC m_DC; //用于存放背景图片的内存DC
BOOL CTransWindowDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
///////////////////////////////////////
//段会锋添加的代码
//实现背景图以及窗口透明
//调用背景图片
CBitmap bitmap;
BITMAP bitInfo;
bitmap.LoadBitmap(IDB_BACKGROUND);
//得到图片大小并调整窗口大小适应图片
bitmap.GetBitmap(&bitInfo);
CRect rect;
GetWindowRect(&rect);
rect.right = rect.left bitInfo.bmWidth;
rect.bottom = rect.top bitInfo.bmHeight;
MoveWindow(rect);
//创建并保存DC
m_DC.CreateCompatibleDC(GetDC());
m_oldBitmap = m_DC.SelectObject(&bitmap);
//设置窗口掩码颜色和模式
//首先获得掩码颜色
COLORREF maskColor = m_DC.GetPixel(0,0);
#define LWA_COLORKEY 0x00000001
#define WS_EX_LAYERED 0x00080000
typedef BOOL (WINAPI *lpfnSetLayeredWindowAttributes)(HWND hWnd,
COLORREF crKey,
BYTE bAlpha,
DWORD dwFlags);
lpfnSetLayeredWindowAttributes SetLayeredWindowAttributes;
HMODULE hUser32 = GetModuleHandle("user32.dll");
SetLayeredWindowAttributes = (lpfnSetLayeredWindowAttributes)GetProcAddress(hUser32,
"SetLayeredWindowAttributes");
SetWindowLong(GetSafeHwnd(),
GWL_EXSTYLE,
GetWindowLong(GetSafeHwnd(),
GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(GetSafeHwnd(),
maskColor,
255,
LWA_COLORKEY);
FreeLibrary(hUser32);
////////////////////////////////////////
return TRUE; // 除非设置了控件的焦点,否则返回 TRUE
}
就像注释的那样,我们首先把图片Load进来,然后把m_DC创建一个与窗口DC兼容的DC,并把刚才Load进来的图片绑定到该内存DC上,并用m_oldBitmap 记录下原有Bitmap,用户最后释放。
void CTransWindowDlg::OnPaint()
{
if (IsIconic())
{
//这里是MFC的框架代码,为了减少篇幅省略…
}
else
{
////////////////////////////////////
//段会锋修改的代码,用于绘制背景图片
//CDialog::OnPaint();
CDC * pDC = this->GetDC();
CRect rect;
GetWindowRect(&rect);
pDC->BitBlt(0,0,rect.Width(),rect.Height(),&m_DC,0,0,SRCCOPY);
////////////////////////////////////
}
}
void CTransWindowDlg::OnClose()
{
////////////////////////////////////
//段会锋添加的代码
//释放资源
CBitmap * bitmap = m_DC.SelectObject(m_oldBitmap);
m_DC.DeleteDC();
bitmap->DeleteObject();
////////////////////////////////////
CDialog::OnClose();
}
BOOL CTransWindowDlg::OnEraseBkgnd(CDC* pDC)
{
////////////////////////////////////
//段会锋编辑的代码
//防止开始绘制的一下闪烁
//return CDialog::OnEraseBkgnd(pDC);
return true;
////////////////////////////////////
}
void CTransWindowDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
///////////////////////////////////
//段会锋添加的代码,双击窗口关闭Windows
this->PostMessage(WM_CLOSE);
///////////////////////////////////
CDialog::OnLButtonDblClk(nFlags, point);
}