原理探究
Windows 提供了一种叫做"窗口区域"(Window Region)的机制,允许我们自定义窗口的可见区域。通过设置窗口区域,我们可以创建出各种形状的窗口,甚至是带有透明区域的镂空窗口。
实现这个功能主要涉及以下 Win32 API:文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
- SetWindowRgn: 设置窗口的区域
- CreateRectRgn: 创建矩形区域
- CombineRgn: 组合多个区域
- GetWindowRgn: 获取窗口当前的区域
- SetWindowLong: 修改窗口的样式
实现方案
1. SetWindowRgn 和 GetWindowRgn 获取当前窗口区域
C++
HRGN hrgnWindow;
//……
SetWindowRgn(hwnd, hrgnWindow, TRUE);
int res = GetWindowRgn(hwnd, hrgnWindow);
if (res == ERROR) {
DeleteObject(hrgnWindow);
return;
}
//……
- 当创建一个新窗口时,它默认没有设置特定的窗口区域。在这种情况下,窗口的可见区域就是整个客户区域。
- 如果窗口没有设置过区域(即从未调用过 SetWindowRgn),GetWindowRgn 通常会返回 ERROR。 一旦调用过 SetWindowRgn,GetWindowRgn 就能够获取到设置的区域。
- 先调用 SetWindowRgn 再调用 GetWindowRgn 的模式,原因如下:确保有区域可以获取:如前所述,如果没有设置过区域,GetWindowRgn 可能会失败;初始化窗口形状:通常我们需要先设置一个初始的窗口形状,然后在此基础上进行修改。
2. CombineRgn 合成不规则区域
C++
CombineRgn(hrgnWindow, hrgnWindow, hrgn, iMode);
重点是最后一个参数,iMode 参数表示组合模式。文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
3. SetWindowRgn 将组合后的新区域设置为窗口的区域
C++
SetWindowRgn(hwnd, hrgnWindow, TRUE);
当我们改变窗口区域时,Windows 会自动触发窗口的重绘。这就是为什么在调用 SetWindowRgn 时将最后一个参数设置为 TRUE。文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
4. SetWindowLong 修改窗口的样式
C++
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT | WS_EX_LAYERED);
如果在前面通过 CombineRgn 将窗口区域设置为镂空的,其实就已经实现了鼠标点击事件的穿透。当然也可以用 SetWindowLong 直接设置鼠标穿透~文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
注意
在函数结束时要调用了 DeleteObject(hrgnWindow),因为 GDI 对象(如区域)需要手动释放,否则可能导致资源泄漏。文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
实现效果
文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
总结
通过使用 Win32 API 中的区域相关函数,我们可以创建出各种形状的窗口,突破传统矩形窗口的限制。这为 UI 设计提供了更多的可能性,可以创建各种有趣的 UI 效果,例如:不规则形状的界面或弹出窗口、带有透明区域的镂空窗口等。还有很多酷炫的效果待我再好好研究研究嘿嘿文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html 文章源自灵鲨社区-https://www.0s52.com/bcjc/cyyjc/16407.html
评论