如何修改widget上指定区域属性,实现选中矩形区域透明其余区域不透明?
完全可以实现,核心思路是通过「不规则窗口形状裁剪」或者「窗口alpha通道掩码」实现选中区域挖空,其余区域保留不透明属性。
通用实现逻辑
- 首先要给你的顶层窗口开启分层透明属性,这是实现局部透明能看到下层内容的基础:Windows下要给窗口加
WS_EX_LAYERED扩展属性,macOS要设置窗口的isOpaque为NO、backgroundColor为clear,Linux X11需要开启Composite扩展支持。 - 维护一个和窗口尺寸一致的掩码位图/路径对象:默认所有区域都设为不透明值,当用户拖拽生成选择矩形后,把对应矩形区域的像素/路径值设为透明。
- 把生成的掩码设置给窗口,系统会自动仅显示掩码中非透明的区域,透明区域直接穿透显示下层桌面/其他窗口内容,完全符合你描述的效果。
常见框架核心实现代码参考
Qt 框架
调用setMask接口即可快速实现:
// 开启窗口基础属性 this->setAttribute(Qt::WA_TranslucentBackground); this->setWindowFlags(Qt::FramelessWindowHint); // 生成掩码 QPixmap mask(this->size()); mask.fill(Qt::black); // 默认全部不透明 QPainter painter(&mask); painter.setCompositionMode(QPainter::CompositionMode_Source); // 将用户选中的矩形区域设为透明 painter.fillRect(selectRect, Qt::transparent); painter.end(); // 给窗口应用掩码 this->setMask(mask);
Win32 原生开发
通过区域合并接口实现裁剪:
// 创建整个窗口的全尺寸区域 HRGN wndRgn = CreateRectRgn(0, 0, wndWidth, wndHeight); // 创建用户选中的矩形区域 HRGN selectRgn = CreateRectRgn(selectLeft, selectTop, selectRight, selectBottom); // 从全窗口区域中减去选中区域,剩下的就是需要保留的不透明区域 CombineRgn(wndRgn, wndRgn, selectRgn, RGN_XOR); // 给窗口设置裁剪区域 SetWindowRgn(hwnd, wndRgn, TRUE); // 释放GDI对象 DeleteObject(selectRgn); DeleteObject(wndRgn);
Electron 环境
调用窗口的setShape接口实现:
const win = new BrowserWindow({ transparent: true, frame: false }) // 仅保留选中区域之外的四个区块显示,选中区域自动透明穿透 win.setShape([ {x: 0, y: 0, width: selectLeft, height: win.getBounds().height}, {x: selectRight, y: 0, width: win.getBounds().width - selectRight, height: win.getBounds().height}, {x: selectLeft, y: 0, width: selectRect.width, height: selectTop}, {x: selectLeft, y: selectBottom, width: selectRect.width, height: win.getBounds().height - selectBottom} ])
注意事项
- 支持多区域选中、不规则选中,只要把掩码中对应的区域设为透明即可,不限于矩形。
- 拖拽过程中可以实时更新掩码,就能实现实时的挖空预览效果,性能够满足普通使用场景。
- 部分Linux桌面环境默认关闭了窗口透明效果,需要用户手动开启桌面合成器才能正常显示。
内容的提问来源于stack exchange,提问作者オパラ
相关产品推荐
相关产品推荐

