今天终于完成一个小心结,以前看到鱼鱼桌面秀那里那么炫的界面就想自己做一回,但是苦于没有实现思路,今天终于有了点眉目了。其实那些桌面秀的界面都是不规则的窗口,以前也有想过实现做不规则窗口,但由于各种原因没动手都没有完成。经过这两天来的搜索,终于完全明白怎么回事了。
要实现不规则窗口,有几种方法。
第一种是基于GDI的,这种方法是根据图片或者其他图案生成一个窗口区域也就是RGN,然后通过SetWindowRgn来得到不规则窗口的区域,然后在重绘窗口的时候就画那张图就可以了,这种方法实现起来比较复杂,因为要得到不规则区域比较困难。
第二方法是基于GDI+的,GDI+是在增强的GDI,扩展了很多的功能,支持多种图片的格式,不再是只有BITMAP让你苦恼,是一套C++的接口,所以操作都是通过类实现的。利用GDI+的方法跟第一种方法有一点是相似的,就是要在重绘窗口的时候画图,但不同的是它不需要创建不规则窗口区域,还有重绘的时候也不是DC间的直接拷贝,而是通过一个叫做UpdateLayerWindow的函数来实现的,这个函数从WINDOWS2000后的系统才有,而且使用的时候如果是VC6而没有装SDK的话要用LoadLibrary的方法得到函数指针调用。这种方法其实是利用WINDOWS的一种叫层次窗口的东西,这种窗口,通过它可以实现半透明效果。最常操作这种窗口的API就是SetLayeredWindowAttributes和UpdateLayerWindow函数。之前我有接过这两个函数,但没深入研究到不规则窗口上,遗憾!另外要实现不规则窗口还要把窗口的样式属性设置成WS_EX_LAYERED, 不然的话是不能成功的,WS_EX_LAYERED的值是0x80000,在网上看到很多文章都是直接写上这个值,根本不知道它实际的含义,估计都是在用VC6编程,呵呵。
好了,下面来用一个实例来讲讲我如何实现不规则窗口的,这东西还是从一些前辈上学到的,我只不过把原理再说一下,根据自身的体会跟大家分享一下而已,在这里要感谢那些前辈们了。这里只是实现一个不规则的窗口,其他功能暂不提供。下面是窗口的截图,这图从一前辈那弄的,具体的原创是谁就搞不清楚了。
从图中可以看到半透明效果,图片是PNG格式的,我另外加上了鼠标单击移动窗口,这是个基于WINDOWS的SDK应用程序,不是使用MFC,这做的过程也遇到窗口样式设置的问题,下面一些关键代码:
//窗口句柄
HWND g_hWnd = NULL;
//背景图
Image *g_pImageBack;
//透明度颜色混合选项
BLENDFUNCTION g_Blend;
//背景图的宽度和高度
int g_BakWidth, g_BakHeight;
更新窗口函数:
void Update()
{
HDC hdcTemp= ::GetDC(g_hWnd);
HDC hdcMemory=CreateCompatibleDC(hdcTemp);
HBITMAP hBitMap=CreateCompatibleBitmap(hdcTemp, g_BakWidth, g_BakHeight);
SelectObject(hdcMemory, hBitMap);
HDC hdcScreen=::GetDC (g_hWnd);
RECT rct;
::GetWindowRect(g_hWnd, &rct);
POINT ptWinPos={rct.left,rct.top};
Graphics graph(hdcMemory);
Point points[] = { Point(0, 0),
Point(g_BakWidth, 0),
Point(0, g_BakHeight)
};
graph.DrawImage(g_pImageBack, points, 3);
POINT ptDst;
ptDst.x = rct.left;
ptDst.y = rct.top;
SIZE size={g_BakWidth, g_BakHeight};
POINT pt;
pt.x = 0;
pt.y = 0;
//设置成层次窗口
DWORD dwExStyle = GetWindowLong(g_hWnd,GWL_EXSTYLE);
if((dwExStyle & WS_EX_LAYERED) != WS_EX_LAYERED)
{//WS_EX_LAYERED是0x00080000
SetWindowLong(g_hWnd, GWL_EXSTYLE,dwExStyle ^ WS_EX_LAYERED);
}
//更新窗口
if (!UpdateLayeredWindow( g_hWnd, hdcScreen, &ptWinPos,
&size, hdcMemory, &pt, 0, &g_Blend, 2))
{
DWORD dwError = ::GetLastError();
printf("failed");
}
//释放资源
graph.ReleaseHDC(hdcMemory);
::DeleteObject(hBitMap);
::DeleteDC(hdcMemory);;
::ReleaseDC(g_hWnd, hdcTemp);
::ReleaseDC(g_hWnd, hdcScreen);
}
要注意上面两个地方:
(1)