Qt 无边框窗口实现拖动与窗口控制(最小化/最大化/关闭)

发布于:2025-06-02 ⋅ 阅读:(19) ⋅ 点赞:(0)

在 Qt 中,使用 Qt::FramelessWindowHint 可以创建无边框窗口,但这样会导致窗口无法拖动,并且系统默认的标题栏按钮(最小化、最大化、关闭)也会消失。本文将介绍如何实现无边框窗口的鼠标拖动功能,并添加自定义最小化、最大化和关闭按钮


1. 设置无边框窗口

首先,在 MainWindow 的构造函数中移除默认边框:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    ui->setupUi(this);
    
    // 设置无边框窗口
    setWindowFlags(Qt::FramelessWindowHint);
    
    // 连接按钮信号(最小化、最大化/还原、关闭)
    connect(ui->toolButton_minimize, &QToolButton::clicked, this, &MainWindow::showMinimized);
    connect(ui->toolButton_maximize, &QToolButton::clicked, this, [this]() {
        if (this->isMaximized()) {
            this->showNormal();  // 如果已最大化,则还原
        } else {
            this->showMaximized();  // 否则最大化
        }
    });
    connect(ui->toolButton_close, &QToolButton::clicked, this, &MainWindow::close);
}

这里:

  • toolButton_minimize 是最小化按钮
  • toolButton_maximize 是最大化/还原切换按钮
  • toolButton_close 是关闭按钮

2. 实现窗口拖动功能

由于无边框窗口无法拖动,我们需要手动处理鼠标事件:

  1. MainWindow 类中添加成员变量和重写鼠标事件
// MainWindow.h
protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;

private:
    QPoint m_dragPosition;  // 记录鼠标按下时的位置
  1. 实现鼠标事件
// MainWindow.cpp
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    }
    QMainWindow::mousePressEvent(event);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPos() - m_dragPosition);  // 移动窗口
        event->accept();
    }
    QMainWindow::mouseMoveEvent(event);
}
  • mousePressEvent:当鼠标左键按下时,记录当前鼠标位置相对于窗口左上角的偏移量。
  • mouseMoveEvent:当鼠标左键按下并移动时,计算窗口新位置并移动窗口。

3. 完整代码示例

MainWindow.h

#include <QMainWindow>
#include <QMouseEvent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;

private:
    Ui::MainWindow *ui;
    QPoint m_dragPosition;
};

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    // 设置无边框窗口
    setWindowFlags(Qt::FramelessWindowHint);
    
    // 连接按钮信号
    connect(ui->toolButton_minimize, &QToolButton::clicked, this, &MainWindow::showMinimized);
    connect(ui->toolButton_maximize, &QToolButton::clicked, this, [this]() {
        if (this->isMaximized()) {
            this->showNormal();  // 还原
        } else {
            this->showMaximized();  // 最大化
        }
    });
    connect(ui->toolButton_close, &QToolButton::clicked, this, &MainWindow::close);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    }
    QMainWindow::mousePressEvent(event);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        move(event->globalPos() - m_dragPosition);
        event->accept();
    }
    QMainWindow::mouseMoveEvent(event);
}

4. 效果

  • 窗口无边框,可以拖动。
  • 点击最小化按钮,窗口最小化到任务栏。
  • 点击最大化按钮,窗口全屏;再次点击还原。
  • 点击关闭按钮,窗口关闭。

5. 进阶优化

  1. 限制拖动区域
    如果只想让窗口的某个区域(如标题栏)可拖动,可以修改 mousePressEvent

    if (event->button() == Qt::LeftButton && ui->titleBarWidget->geometry().contains(event->pos())) {
        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
        event->accept();
    }
    
  2. 双击最大化/还原
    可以重写 mouseDoubleClickEvent 实现双击标题栏最大化/还原。

  3. 窗口阴影效果
    使用 QGraphicsDropShadowEffect 让无边框窗口看起来更美观。


6. 总结

通过重写 mousePressEventmouseMoveEvent,我们可以实现无边框窗口的拖动功能。结合自定义按钮,可以完全替代系统默认的标题栏,打造更个性化的 UI。


网站公告

今日签到

点亮在社区的每一天
去签到