windows api实现窗口透明整理

1. 实现窗口彻底透明

实现这种效果的方案网上介绍很多,基本原理都一样,在这里还是重复记录一次。
效果图:
这里写图片描述
这种透明效果整个窗口的所有内容全部透明,可以看到图中红色箭头所指,从这个窗口可以看到底层的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);

2.实现背景透明控件不透明一

这种方案其实是实现毛玻璃效果用的,只是偶然发现勉强能够实现透明效果,效果差强人意,如果发现在某些环境下不起作用,那也算正常现象。

效果:
这里写图片描述
可以看到左侧透出来的代码,有一种朦胧的感觉,这可能就是毛玻璃效果吧。

代码实现:
(1) 包含头文件

    #include <dwmapi.h>

(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_);

第一个代码块是实现这种效果的关键所在,这两个代码块的相对位置可以调整。

3.实现背景透明控件不透明正式方案

效果:
这里写图片描述
可以看到,这种背景透明的效果还是比较正常的,看到底层的文字很清晰。

代码实现:
(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,前面一种是将某种颜色(第二个参数)设置为透明,后一种是将窗口所有颜色均设置为指定透明度(第三个参数),具体区别网上搜索一下就出来了。

4.动图显示异常分析

效果
这里写图片描述
图中的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);

在开始显示第一帧图片之前,强制刷新窗口,之后即可恢复正常。

猜你喜欢

转载自blog.csdn.net/zhuiyuanqingya/article/details/80844258