在 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. 实现窗口拖动功能
由于无边框窗口无法拖动,我们需要手动处理鼠标事件:
- 在
MainWindow
类中添加成员变量和重写鼠标事件:
// MainWindow.h
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
QPoint m_dragPosition; // 记录鼠标按下时的位置
- 实现鼠标事件:
// 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. 进阶优化
限制拖动区域:
如果只想让窗口的某个区域(如标题栏)可拖动,可以修改mousePressEvent
:if (event->button() == Qt::LeftButton && ui->titleBarWidget->geometry().contains(event->pos())) { m_dragPosition = event->globalPos() - frameGeometry().topLeft(); event->accept(); }
双击最大化/还原:
可以重写mouseDoubleClickEvent
实现双击标题栏最大化/还原。窗口阴影效果:
使用QGraphicsDropShadowEffect
让无边框窗口看起来更美观。
6. 总结
通过重写 mousePressEvent
和 mouseMoveEvent
,我们可以实现无边框窗口的拖动功能。结合自定义按钮,可以完全替代系统默认的标题栏,打造更个性化的 UI。