实现这种效果的方案网上介绍很多,基本原理都一样,在这里还是重复记录一次。
效果图:
这种透明效果整个窗口的所有内容全部透明,可以看到图中红色箭头所指,从这个窗口可以看到底层的source tree的按钮。
代码实现:
(1)设置WS_EX_LAYERED属性
::ShowWindow(main_window_, nCmdShow);
::UpdateWindow(main_window_);
LONG ret = ::GetWindowLong(main_window_, GWL_EXSTYLE);
ret = ret | WS_EX_LAYERED;
::SetWindowLong(main_window_, GWL_EXSTYLE, ret);
前面两行代码是创建窗口后刷新用的,之后三行代码是设置窗口的分层属性WS_EX_LAYERED,只有设置了这个属性,才能实现上图给出的透明效果,这几行代码的相对位置不可以更改,我试着把后三行代码放到窗口刷新操作之前,代码无法正常运行。
(2)在窗口过程函数中响应WM_PAINT时加上
::SetLayeredWindowAttributes(main_window_, 0, 255, LWA_ALPHA);
这种方案其实是实现毛玻璃效果用的,只是偶然发现勉强能够实现透明效果,效果差强人意,如果发现在某些环境下不起作用,那也算正常现象。
效果:
可以看到左侧透出来的代码,有一种朦胧的感觉,这可能就是毛玻璃效果吧。
代码实现:
(1) 包含头文件
#include
(2) 添加编译链接
#pragma comment(lib,"Dwmapi.lib")
(3) 设置窗口的背景颜色
wcex.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
备注:窗口背景颜色设置为某些颜色无法透明,上图效果是设置为灰色时实现的。
(4) 在窗口初始化时加上如下代码
MARGINS m = { -1 };
DwmExtendFrameIntoClientArea(main_window_, &m);
::ShowWindow(main_window_, nCmdShow);
::UpdateWindow(main_window_);
第一个代码块是实现这种效果的关键所在,这两个代码块的相对位置可以调整。
效果:
可以看到,这种背景透明的效果还是比较正常的,看到底层的文字很清晰。
代码实现:
(1) 设置窗口背景颜色
wcex.hbrBackground = CreateSolidBrush(RGB(251, 255, 242));
这里设置了一种我需要显示的图片里没有的颜色作为背景颜色,后面将看到实现透明的原理是将指定的颜色设为透明。
(2) 初始化设置窗口的WS_EX_LAYERED属性
这里和第一种方案的设置方式是一样,还是复制一次:
::ShowWindow(main_window_, nCmdShow);
::UpdateWindow(main_window_);
LONG ret = ::GetWindowLong(main_window_, GWL_EXSTYLE);
ret = ret | WS_EX_LAYERED;
::SetWindowLong(main_window_, GWL_EXSTYLE, ret);
(3)在窗口的过程函数中响应WM_PAINT消息,增加如下代码
::SetLayeredWindowAttributes(main_window_, RGB(251, 255, 242), 0, LWA_COLORKEY);
注意这里设置的是LWA_COLORKEY,而不是LWA_ALPHA,前面一种是将某种颜色(第二个参数)设置为透明,后一种是将窗口所有颜色均设置为指定透明度(第三个参数),具体区别网上搜索一下就出来了。
效果
图中的gif图片显示异常,很明显错位了。第一帧显示位置,与后面的帧的显示位置相差极大。
原因分析:
窗口去除边框和标题栏是通过处理WM_SIZE消息实现的,第一帧显示时很明显是在有边框和标题栏的情况下的,而后面的帧在显示时边框和标题栏已经消失了,所以后面的帧显示位置就往左上移动了。也就是说去除窗口边框和标题栏的时机过晚,需要在开始显示gif图片之前通知窗口刷新。
case WM_SIZE:
{
LONG_PTR Style = ::GetWindowLongPtr(hWnd, GWL_STYLE);
Style = Style & ~WS_CAPTION &~WS_SYSMENU &~WS_SIZEBOX;
::SetWindowLongPtr(hWnd, GWL_STYLE, Style);
return 0;
}
解决办法:
::InvalidateRect(hWnd, NULL, TRUE);
::UpdateWindow(hWnd);
在开始显示第一帧图片之前,强制刷新窗口,之后即可恢复正常。