You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Qt无边框窗口如何保留操作按钮并设置圆角?

实现带自定义操作按钮的圆角无边框Qt窗口

嘿,我之前做Qt项目的时候也碰到过一模一样的问题!用setWindowFlags(Qt::Window | Qt::FramelessWindowHint)之后,系统自带的标题栏、操作按钮全没了,还要自己搞定圆角窗口和自定义按钮,对吧?别慌,我给你一步步拆解怎么实现:

1. 先搞定圆角窗口

去掉系统边框后,Qt默认不会渲染圆角,得自己动手。这里有两种靠谱的实现方式:

方法一:重写paintEvent绘制圆角

这种方法灵活性更高,适合需要复杂绘制的场景:

#include <QPainter>
#include <QPainterPath>

void YourMainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing); // 开启抗锯齿,让圆角更平滑

    // 绘制圆角路径,参数12是圆角半径,按需调整
    QPainterPath path;
    path.addRoundedRect(this->rect(), 12, 12);

    // 设置裁剪区域,超出圆角的部分会被切掉
    painter.setClipPath(path);

    // 调用父类的paintEvent,保证窗口内容正常绘制
    QMainWindow::paintEvent(event);
}

方法二:用样式表+透明背景

这种方法更简单,适合快速实现:
首先给窗口设置透明背景属性(必须配合无边框使用):

this->setAttribute(Qt::WA_TranslucentBackground);

然后给窗口添加样式表(注意指定窗口的类名或objectName,避免影响子控件):

QMainWindow#YourMainWindow {
    background-color: #ffffff; /* 设置窗口背景色 */
    border-radius: 12px; /* 圆角半径 */
}

小提示:如果你的窗口是QWidget而不是QMainWindow,把选择器改成QWidget#YourWidget就行。另外要确保子控件背景设为透明,避免覆盖窗口圆角效果。

2. 添加自定义窗口操作按钮

系统标题栏没了,我们得自己做最小化、最大化/还原、关闭这三个按钮:

步骤1:创建按钮并关联槽函数

#include <QPushButton>
#include <QHBoxLayout>

// 把这个初始化函数放在窗口构造函数里调用
void YourMainWindow::initTitleBarButtons()
{
    // 最小化按钮
    QPushButton* minBtn = new QPushButton(this);
    minBtn->setIcon(QIcon(":/icons/minimize.svg")); // 替换成你的图标路径,也可以用文字"-"
    minBtn->setFixedSize(30, 30); // 设置按钮大小
    connect(minBtn, &QPushButton::clicked, this, &QMainWindow::showMinimized);

    // 最大化/还原按钮
    QPushButton* maxBtn = new QPushButton(this);
    maxBtn->setIcon(QIcon(":/icons/maximize.svg"));
    maxBtn->setFixedSize(30, 30);
    connect(maxBtn, &QPushButton::clicked, [this, maxBtn](){
        if (this->isMaximized()) {
            this->showNormal();
            maxBtn->setIcon(QIcon(":/icons/restore.svg"));
        } else {
            this->showMaximized();
            maxBtn->setIcon(QIcon(":/icons/maximize.svg"));
        }
    });

    // 关闭按钮
    QPushButton* closeBtn = new QPushButton(this);
    closeBtn->setObjectName("closeBtn"); // 给按钮设置唯一标识,方便样式表匹配
    closeBtn->setIcon(QIcon(":/icons/close.svg"));
    closeBtn->setFixedSize(30, 30);
    connect(closeBtn, &QPushButton::clicked, this, &QMainWindow::close);

    // 把按钮放到水平布局里
    QHBoxLayout* btnLayout = new QHBoxLayout();
    btnLayout->addWidget(minBtn);
    btnLayout->addWidget(maxBtn);
    btnLayout->addWidget(closeBtn);
    btnLayout->setSpacing(0);
    btnLayout->setContentsMargins(0, 0, 10, 0); // 右边留10px边距

    // 搭建标题栏布局,把按钮挤到右上角
    QWidget* titleBar = new QWidget(this);
    QHBoxLayout* titleBarLayout = new QHBoxLayout(titleBar);
    titleBarLayout->addStretch(); // 左侧拉伸占位
    titleBarLayout->addLayout(btnLayout);
    titleBarLayout->setContentsMargins(0, 0, 0, 0);
    titleBar->setFixedHeight(30); // 设置标题栏高度

    // 把标题栏放到主窗口顶部
    this->setMenuWidget(titleBar);
}

步骤2:美化按钮样式

给按钮加hover效果,提升交互体验,添加样式表:

QPushButton {
    border: none;
    background-color: transparent;
    icon-size: 16px; /* 调整图标大小 */
}
QPushButton:hover {
    background-color: #f5f5f5;
    border-radius: 4px; /* 按钮hover时的圆角 */
}
QPushButton#closeBtn:hover {
    background-color: #ff4c4c;
    /* 如果用SVG图标,可以设置hover时的颜色 */
    filter: invert(1) brightness(2);
}

3. 补充:实现窗口拖拽功能

无边框窗口默认不能拖拽移动,我们自己实现这个功能:

// 在窗口类的头文件里添加私有成员变量
private:
    QPoint m_dragStartPos;

// 重写鼠标事件
void YourMainWindow::mousePressEvent(QMouseEvent *event)
{
    // 只有点击标题栏区域(y坐标小于标题栏高度)才允许拖拽
    if (event->button() == Qt::LeftButton && event->pos().y() <= 30) {
        m_dragStartPos = event->globalPos() - this->frameGeometry().topLeft();
        event->accept();
    }
}

void YourMainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        this->move(event->globalPos() - m_dragStartPos);
        event->accept();
    }
}

这样用户点击标题栏区域就能拖拽窗口,避免整个窗口都能拖动的尴尬。

最后注意事项

  • 如果用了Qt::WA_TranslucentBackground,要确保窗口没有设置Qt::WA_OpaquePaintEvent属性,否则透明效果会失效。
  • 最大化窗口时,圆角会被屏幕边缘覆盖,这是正常现象;如果想最大化时也保留圆角,可以在showMaximized时调整窗口大小,给屏幕边缘留一点空隙。

内容的提问来源于stack exchange,提问作者Hhry

火山引擎 最新活动