如何在不使用FramelessWindowHint的情况下让WA_TranslucentBackground在Windows生效?
我尝试用setAttribute(Qt::WA_TranslucentBackground);让QMainWindow背景透明,但发现这个属性仅在以下两种情况之一生效:
- 同时设置
setWindowFlag(Qt::FramelessWindowHint); - GUI中至少包含一个
QOpenGLWidget
我没有QOpenGLWidget使用经验,想知道能否通过QSurfaceFormat这类方式实现和添加QOpenGLWidget相同的效果,让透明属性生效;或者有没有除设置FramelessWindowHint标志、创建QOpenGL部件之外的其他方案?
目前我发现创建QOpenGLWidget后调用opengl->deleteLater()能让WA_TranslucentBackground生效,但每个窗口会多占用50MB内存,我需要创建多个这样的窗口,因此寻求替代方案。
附带示例代码:
int main(int argc, char *argv[]) { QApplication a(argc, argv); /* QSurfaceFormat format; format.setAlphaBufferSize(8); QSurfaceFormat::setDefaultFormat(format); QSurfaceFormat format; format.setAlphaBufferSize(8); format.setSamples(16); format.setSwapBehavior(QSurfaceFormat::DoubleBuffer); format.setRenderableType(QSurfaceFormat::OpenGL); format.setProfile(QSurfaceFormat::CoreProfile); QSurfaceFormat::setDefaultFormat(format); */ MainWindow w; w.show(); return a.exec(); } //mainwindow.h #include <QtWidgets/QMainWindow> #include "ui_MainWindow.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindowClass; }; QT_END_NAMESPACE class MainWindow : public QMainWindow{ Q_OBJECT public: MainWindow(QWidget* parent = nullptr); } //mainwindow.cpp MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowClass()) { ui->setupUi(this); setAttribute(Qt::WA_TranslucentBackground); QGridLayout* layout = new QGridLayout(); ui->centralWidget->setStyleSheet("background-color: transparent;"); ui->centralWidget->setLayout(layout); QWidget* widget = new QWidget(this); widget->setStyleSheet("background-color: green; border-radius: 32px;"); layout->addWidget(widget); //QOpenGLWidget* opengl = new QOpenGLWidget(this); //opengl->deleteLater(); }
方案1:组合使用WA_NoSystemBackground与透明属性
如果窗口不需要系统默认的背景绘制,可以同时启用Qt::WA_NoSystemBackground和Qt::WA_TranslucentBackground,无需依赖QOpenGLWidget或无边框标志:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowClass()) { ui->setupUi(this); setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_TranslucentBackground); QGridLayout* layout = new QGridLayout(); ui->centralWidget->setStyleSheet("background-color: transparent;"); ui->centralWidget->setLayout(layout); QWidget* widget = new QWidget(this); widget->setStyleSheet("background-color: green; border-radius: 32px;"); layout->addWidget(widget); }
该方式会让窗口完全跳过系统背景绘制,需确保所有子部件都正确设置背景(透明或自定义颜色),避免绘制异常。
方案2:强制启用离屏渲染
通过设置离屏渲染相关属性,让窗口支持透明效果,无需OpenGL部件:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowClass()) { ui->setupUi(this); setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_OpaquePaintEvent, false); // 禁用不透明绘制事件 setAttribute(Qt::WA_TransparentForMouseEvents, false); // 确保窗口接收鼠标事件 QGridLayout* layout = new QGridLayout(); ui->centralWidget->setStyleSheet("background-color: transparent;"); ui->centralWidget->setLayout(layout); QWidget* widget = new QWidget(this); widget->setStyleSheet("background-color: green; border-radius: 32px;"); layout->addWidget(widget); } // 重写paintEvent确保自定义绘制逻辑 void MainWindow::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 按需绘制窗口背景(如半透明效果),或交由子部件负责绘制 }
此方案通过强制窗口使用支持Alpha的离屏缓冲区实现透明,内存占用远低于创建QOpenGLWidget。
方案3:替换默认中心部件为透明容器
彻底替换QMainWindow的默认centralWidget为自定义透明容器,避免默认部件的背景干扰:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindowClass()) { ui->setupUi(this); setAttribute(Qt::WA_TranslucentBackground); // 移除默认中心部件,替换为透明容器 delete ui->centralWidget; QWidget* transparentCentral = new QWidget(this); transparentCentral->setStyleSheet("background-color: transparent;"); setCentralWidget(transparentCentral); QGridLayout* layout = new QGridLayout(transparentCentral); QWidget* widget = new QWidget(this); widget->setStyleSheet("background-color: green; border-radius: 32px;"); layout->addWidget(widget); }
该方案通过清除默认部件的背景影响,配合透明属性实现效果,无需额外依赖。
关于QSurfaceFormat的说明
单纯设置QSurfaceFormat(如Alpha缓冲区大小)无法直接触发WA_TranslucentBackground生效,因为该属性的生效逻辑与窗口的渲染上下文绑定——只有当窗口使用支持Alpha的渲染上下文时才会生效,而QOpenGLWidget的作用就是强制创建此类上下文。若直接为窗口设置OpenGL上下文,操作复杂度高且内存收益不明显,不推荐。
内容的提问来源于stack exchange,提问作者Cesar

