编译环境
WIN2000以上操作系统,VC++6.0。
技术原理
如何实现透明窗口
首先,从CWnd派生一个类 CfloatWnd,在Create 函数里加载位图,在OnPaint函数里绘制位图,详见源代码 。
使用SetLayeredWindowAttributes可以方便的制作透明窗体,此函数在w2k以上才支持,而且如果希望直接使用的话,可能需要下载最新的SDK。不过此函数在w2k的user32.dll里有实现,所以如果你不希望下载巨大的sdk的话,可以直接使用GetProcAddress获取该函数的指针。
SetLayeredWindowAttributes的函数原型如下:
BOOL SetLayeredWindowAttributes(
HWND hwnd, // handle to the layered window COLORREF crKey, // specifies the color key BYTE bAlpha, // value for the blend function DWORD dwFlags // action ); Windows NT/2000/XP: Included in Windows 2000 and later. Windows 95/98/Me: Unsupported.(注意了,在win9x里没法使用的) Header: Declared in Winuser.h; include Windows.h. Library: Use User32.lib. |
一些常量
:
WS_EX_LAYERED = 0x80000; LWA_ALPHA = 0x2; LWA_COLORKEY=0x1; |
其中dwFlags有LWA_ALPHA和
LWA_COLORKEY
LWA_ALPHA被设置的话,通过bAlpha决定透明度 .
LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示 .
要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000).
LWA_ALPHA被设置的话,通过bAlpha决定透明度 .
LWA_COLORKEY被设置的话,则指定被透明掉的颜色为crKey,其他颜色则正常显示 .
要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性(旧的sdk没有定义这个属性,所以可以直接指定为0x80000).
例子代码
:
1. 重载int CFloatWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
1. 重载int CFloatWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
//
加入
WS_EX_LAYERED
扩展属性
SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
//
加载动态库
User32.DLL
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC fun = NULL;
//
取得
SetLayeredWindowAttributes
函数指针
fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
if(fun)fun(this->GetSafeHwnd(),0,100,2);
FreeLibrary(hInst);
}
m_iCount=0;
//
用
WINDOWS
时钟和
SetLayeredWindowAttributes
函数实现淡入淡出的透明效果
this->SetTimer(1,10,0);
return 0;
|
2. 重载void CFloatWnd::OnTimer(UINT nIDEvent)
// m_bAdd
是表示颜色是加深还是减浅的标志
if(m_bAdd)
{
m_iCount++;
if(m_iCount>=255)
{
m_bAdd=false;
}
}else
{
m_iCount--;
if(m_iCount<=0)
{
m_bAdd=true;
}
}
HINSTANCE hInst = LoadLibrary("User32.DLL");
if(hInst)
{
typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC fun = NULL;
//
取得
SetLayeredWindowAttributes
函数指针
fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
if(fun)fun(this->GetSafeHwnd(),0,m_iCount,2);
FreeLibrary(hInst);
}
CWnd::OnTimer(nIDEvent);
|
如何实现浮动
实现浮动有很多方法,可以用钩子函数来做。我采用一种比较简便的方法,就是让操作系统误认为窗口是非客户区的方法。
1.
重载UINT CFloatWnd::OnNcHitTest(CPoint point)函数
CWnd::OnNcHitTest(point);
//
始终返回
非客户区的标题区域
return HTCAPTION ;
|
注意:打开CLASSWIZAR,找到CfloatWnd类,在CLASS INFO 标签项下有个MESSAGE FILTER ,选择为WINDOW选项,就可以出现WM_NCHITTEST消息。
2.
重载void CFloatWnd::OnNcLButtonDown(UINT nHitTest, CPoint point)
//
调整窗口位置
CRect rt,rt1;
this->GetWindowRect(&rt);
CWnd::OnNcLButtonDown(nHitTest, point);
this->GetWindowRect(&rt1);
CPoint pt;
if(GetCursorPos(&pt))
{
if(!rt1.PtInRect(pt))
{
this->MoveWindow(&rt);
}
}
|
这段代码是因为在只是点击窗口而不拖动的情况下,窗口的位置会变的很乱,显示不到屏幕上;不信的话就不重载OnNcLButtonDown,再点击窗口而不拖动的情况下就会找不到窗口了。我就在在此做了权宜的处理,不知哪位高人有更好的方法解决这个问题,请赐教。