在 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_OBJECTpublic: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。