使用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)


» 转载请注明来源及链接:未来代码研究所

» 本文链接地址:http://blog.atelier39.org/winuser/188.html

时间: 2024-09-14 14:03:18

使用Win32 API创建不规则形状&带透明色的窗口的相关文章

电脑如何用系统自带截图工具进行不规则形状截图

  1.打开开始菜单,点击"所有程序(应用)"--附件--截图工具,或者在开始搜索框中输入"截图"或"Snipping tool"再点击打开;     2.点击"新建"旁边的倒三角,选择"任意格式截图";   3.然后画出想要的形状就可以了.   以上就是用电脑自带的截图工具进行不规则形状截图的方法.

win32 api Windows窗口的创建

windows窗口的创建有以下几个步骤: 1.创建注册窗口类 2.创建窗口句柄 3.显示更新窗口 4.消息循环 1.创建注册窗口类 所谓创建窗口类就是定义一个WNDCLASS类对象,并将该对象进行初始化.之后就要用RegisterClass()函数对该窗口类对象进行注册,以便使某个窗口与该窗口类相关联. 关于WNDCLASS的定义如下:  typedef struct {    UINT style;    WNDPROC lpfnWndProc;    int cbClsExtra;    i

VB.Net创建不规则窗体 Montaque(原作)

 VB.Net创建不规则窗体    Montaque(原作)   一般说来,应用程序的窗体都是规则的,即是矩形窗体.有时候为了某种特殊的用途,我们希望改变应用程序窗体的形状,比如做个个性十足的mp3播放器,小时钟等等,这就需要 "定制"我们的应用程序.另外,特殊形状的窗体有时候也能吸引用户的注意力,使得他们格外注意你的程序. 在VB6里面,我们一般通过以下代码来创建不规则窗体.Private Declare Function SetWindowRgn Lib "user32&

如何在C#中使用Win32 API和其他库

C# 用户经常提出两个问题:"我为什么要另外编写代码来使用内置于 Windows 中的功能?在框架中为什么没有相应的内容可以为我完成这一任务?"当框架小组构建他们的 .NET 部分时,他们评估了为使 .NET 程序员可以使用 Win32 而需要完成的工作,结果发现 Win32 API 集非常庞大.他们没有足够的资源为所有 Win32 API 编写托管接口.加以测试并编写文档,因此只能优先处理最重要的部分.许多常用操作都有托管接口,但是还有许多完整的 Win32 部分没有托管接口. 平台

用Win32 API实现串行通信

串口是常用的计算机与外部串行设备之间的数据传输通道,由于串行通信方便易行,所以应用广泛.我们可以利用Windows API 提供的通信函数编写出高可移植性的串行通信程序. 在Win16中,可以利用OpenComm.CloseComm和WriteComm等函数打开.关闭和读写串口.但在Win32中,串口和其他通信设备均被作为文件处理,串口的打开.关闭和读写等操作所用的API函数与操作文件的函数相同.可通过CreateFile函数打开串口,通过CloseFile函数关闭串口,通过CommProp.D

深入浅出VC++串口编程之基于Win32 API

1.API描述 在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与 文件操作的API一致. 打开串口 Win32 中用于打开串口的API 函数为 CreateFile,其原型为: HANDLE CreateFile ( LPCTSTR lpFileName, //将要打开的串口逻辑名,如COM1 或COM2 DWORD dwAccess, //指定串口访问的类型 ,可以是读取.写入或两者并列 DWORD dwShareMode, //指定共享属性,由于串口不 能共享,该参数

Win32 API实现的组件对象集

本组件实现了七个COM对象: 一.COM组件,实现了两个 Dispatch 接口 Itest(默认接口): 实现了BASE64加解密,发送邮件,以给定分隔字符把字符串转换成数组,钩子安装,设置IIS默认站点的主目录,拷贝文件夹,删除文件夹,创建多级目录,以给定日期计算星期几,得到内存大小,创建快捷方式,注册COM组件,检测WINDOWS版本,得到磁盘剩余空间,得到程序组路径 IOpen: 调用"打开文件"通用对话框,并对其定制,实现了文本文件的预览.调用"浏览"通用

C#创建不规则窗体的几种方式

现在,C#创建不规则窗体不是一件难事,下面总结一下: 一.自定义窗体,一般为规则的图形,如圆.椭圆等. 做法:重写Form1_Paint事件(Form1是窗体的名字),最简单的一种情况如下: System.Drawing.Drawing2D.GraphicsPath shape = new System.Drawing.Drawing2D.GraphicsPath(); shape.AddEllipse(0,0,this.Height, this.Width); this.Region = ne

qt下调用win32 api 对串口编程,怎么弄?主要是怎么调用api

问题描述 qt下调用win32 api 对串口编程,怎么弄?主要是怎么调用api 解决方案 解决方案二: 我用MessageBox测试,出了问题.添加了lib文件,把dll文件放在工程文件夹下了,也还是不行 解决方案三: 我用MessageBox测试,出了问题.添加了lib文件,把dll文件放在工程文件夹下了,也还是不行 解决方案四: user32.lib和kernel32.lib是Windows的标准库,可以直接链接,是不是..libs目录下的库文件与你开发机的Windows版本不一致?去掉"