在Qt中实现类桌宠的无边框窗口

无边框窗口的三个关键设置

窗口类继承自 QWidget,构造函数中只需两句代码就能搭出无边框的骨架:

1
2
3
setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::SubWindow | Qt::FramelessWindowHint |
Qt::WindowStaysOnTopHint);

各参数的作用:

  • WA_TranslucentBackground:允许窗口背景透明,PNG 的透明区域才不会变黑底
  • FramelessWindowHint:去掉系统标题栏和边框
  • WindowStaysOnTopHint:让窗口常驻前景(总在最上层)

这三个标志合起来就能让你的窗口变成一个”浮动的透明图片”。

跨平台的窗口形状处理

如果你想让透明区域真的”穿透”(即鼠标点击透明区域时穿过这个窗口到下层),有两套方案:

Windows 方案

1
this->clearMask();  // 不裁剪窗口形状

选择不主动裁剪窗口形状,避免半透明边缘被硬裁切后出现锯齿或边缘异常。

Linux 方案(X11)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifdef Q_OS_LINUX
Display *display = XOpenDisplay(nullptr);
if (display) {
Window window_id = static_cast<Window>(this->winId());

// 根据图像的 Alpha 通道建立输入区域
QRegion region(QBitmap::fromImage(image.createAlphaMask()));

// 转换为 X11 矩形格式并应用
XRectangle *xrects = new XRectangle[region.rectCount()];
// ... 填充矩形数据 ...

XShapeCombineRectangles(display, window_id, ShapeInput, 0, 0,
xrects, count, ShapeSet, YXBanded);

delete[] xrects;
XCloseDisplay(display);
}
#endif

这个方案使用 X11 Shape 扩展,在系统级别裁剪输入区域,比在 Qt 层处理更彻底。