• 使用Win32 API创建不规则形状&带透明色的窗口


    前一阵突然想起了9月份电面某公司实习时的二面题,大概就是说怎么用Win32 API实现一个透明的窗口,估计当时我的脑残答案肯定让面试官哭笑不得吧。所以本人决定好好研究下这个问题。经过一下午的摸索,基本掌握了使用Win32 API创建各种匪夷所思的窗口的基本思路。

    (以下文字基于本人的个人理解,由于本人技术和经验原因不保证正确性,希望各位不吝指正)

    首先我们需要了解一些基础知识。

    1、Layered Windows。这是Windows2000开始引入的新概念,重新定义了窗口的Hit Testing方法,以前都是把窗口按rectangle的方式裁剪,而把窗口加上WS_EX_LAYERED的Style后就可以根据窗口的形状和像素值进行Hit Testing[1],这样我们的不规则窗口就变成了真正意义上的独立窗口,而不是传统的被一个不可见的矩形窗口所包含。

    Layered Windows支持两种绘制方式,一种是采用UpdateLayeredWindow函数,优点是是一劳永逸,不需要在窗口函数中响应各种重绘事件,缺点嘛大概就是这高科技玩意让人一时半会接受不了= =另一种方式就是先用SetLayeredWindowAttributes函数设置关于窗口透明度的信息,然后用传统方式,在窗口函数中响应各种重绘事件。然而我们其实似乎并不需要关注WM_PAINT,只要在WM_CREATE中初始化一下窗口的全局背景(颜色和SetLayeredWindowAttributes所定义的相同),然后在WM_ERASEBKGND中更新一些颜色与SetLayeredWindowAttributes定义的不同的细节区域之处便可。

    2、SetWindowRgn函数。这个函数用来定义窗口的区域,我们的不规则形状由此而来。这个函数和它的朋友们十分强大,不仅可以定义独立的基本形状的区域,还可以通过运算来组合已有区域从而产生新的区域。下面的实例就通过CombineRgn函数的帮助来产生了一个孔方兄形状的窗口。

    好了,基本知识我们已经掌握了,下面来看看我做的示例程序的运行效果:

    怎么样,还算比较cool吧。下面是完整代码:

    #include <windows.h>

    LRESULT _stdcall WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        static HDC hDC = GetWindowDC(hWnd);
        static HRGN hRgn = CreateRectRgn(120, 70, 280, 230);

        switch(uMsg)
        {
        case WM_ERASEBKGND:
            {
                DefWindowProc(hWnd, uMsg, wParam, lParam);
                FillRgn(hDC, hRgn, CreateSolidBrush(RGB(255, 165, 0))); // Orange
                SelectObject(hDC, hRgn);
                return 0;
            }

        case WM_CREATE:
            {
                HRGN hRgn1 = CreateEllipticRgn(0, 0, 400, 300);
                HRGN hRgn2 = CreateEllipticRgn(150, 100, 250, 200);
                CombineRgn(hRgn1, hRgn1, hRgn2, RGN_XOR);
                SetWindowRgn(hWnd, hRgn1, TRUE);
                DeleteObject(hRgn1);
                 DeleteObject(hRgn2);          
                 break;
             }
     
        case WM_LBUTTONDOWN:
             {
                SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0);
                break;
            }

        case WM_DESTROY:
            {
                DeleteObject(hRgn);
                ReleaseDC(hWnd, hDC);
                PostQuitMessage(0);
                break;
             }
        }
        return DefWindowProc(hWnd, uMsg, wParam, lParam);;
    }

    int _stdcall WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, BOOL)
    {
        WNDCLASS wc = {0};
        wc.lpszClassName = L"wndclass";
        wc.hbrBackground = CreateSolidBrush(RGB(255, 99, 71));
        wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wc.hCursor = LoadCursor(NULL, IDC_ARROW);
        wc.lpfnWndProc = WinProc;
        RegisterClass(&wc);

        HWND hWnd = CreateWindowExW(WS_EX_LAYERED, L"wndclass", L"Window", WS_POPUP|WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, 0, 0, hInstance, 0);
        if (hWnd == NULL)
            return 1;

        SetLayeredWindowAttributes(hWnd, NULL, 178, LWA_ALPHA); // Tomato

        MSG msg = {0};
        while (GetMessage(&msg, 0, 0, 0))
        {
            DispatchMessage(&msg);
        }

        return 0;
    }

    参考资料:
    [1] MSDN:Layered Windows
    [2] WindowsAPI_001:创建一个不规则的窗口的方法(用到Region系列API)

    » 转载请注明来源及链接:未来代码研究所
  • 相关阅读:
    hibernate中持久化对象的生命周期(转载)
    IDEA调试技巧之条件断点
    POI中不推荐的方法与其替代的方法
    visualvm监控类是否是多例模式
    IDEA中Maven项目使用Junit4单元测试的写法
    JPQL的关联查询
    poi的cellstyle陷阱,样式覆盖
    studio 连不上远程仓库的各种原因分析
    Concurrent usage detected
    我的SSH框架实例(附源码)
  • 原文地址:https://www.cnblogs.com/lidabo/p/3437729.html
Copyright © 2020-2023  润新知