目錄
0.背景
1.詳細實現
思路簡介
.h文件
.cpp文件
0.背景
Qt + Linux;項目遇到問題,解決后特此記錄
項目需要,個性化的標題欄(是個widget),在傳統的三個按鈕(最大化、最小化、關閉)的基礎上,新增了標題欄拖拽功能,有個額外要求是:拖拽標題欄的同時,讓窗口變為normal狀態(非最大化,也非最小化),也就是跟網頁差不多的居中效果。
我希望的窗口大小效果:最大化(1920*1080);普通normal狀態(1344*756);最小化(0);
我遇到的問題是:在拖拽時界面從max變為normal時,大小雖然修改為了1344*756,但如果此時我的鼠標在點擊標題欄時,是在normal大小之外(如下圖示意),此時變為normal后,會發現鼠標和窗體是分開的狀態(按住鼠標時仍可拖動),就很怪。
排查后發現是因為【當窗口從最大化狀態恢復為普通大小時,窗口的左上角位置會改變,但鼠標的全局位置保持不變】;
修改思路:在最大化狀態下,記錄鼠標在窗口中的相對位置比例 (xRatio
,?yRatio
);恢復普通窗口后,按相同比例計算鼠標在新窗口中的位置 (newX
,?newY
);計算窗口的新位置?newWindowPos
,使得鼠標在屏幕中的絕對位置保持不變。
修改后normal時鼠標狀態如下:
修改后可以保證鼠標無論點擊標題欄的何處,都是可以平滑的點擊、移動,鼠標不會有點擊后出現在normal窗體外的效果。詳細代碼見下文。
1.詳細實現
思路簡介
就是實現3個按鈕release的事件;然后重寫3個protectes函數;
.h文件
#ifndef BCI_SEEG_STEER_NEW_WIDGET_H
#define BCI_SEEG_STEER_NEW_WIDGET_H#include <QWidget>
#include <QMouseEvent>
#include <QDesktopWidget>namespace Ui {
class BCI_SEEG_Steer_New_Widget;
}class BCI_SEEG_Steer_New_Widget : public QWidget
{Q_OBJECTpublic:explicit BCI_SEEG_Steer_New_Widget(QWidget *parent = nullptr);~BCI_SEEG_Steer_New_Widget();protected:void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;void mouseReleaseEvent(QMouseEvent *event) override;private slots:void on_btn_mini_released();void on_btn_max_released();void on_btn_close_released();private:Ui::BCI_SEEG_Steer_New_Widget *ui;bool m_isDragging = false;///<拖動標題欄QPoint m_dragPosition;
};#endif // BCI_SEEG_STEER_NEW_WIDGET_H
.cpp文件
#include "BCI_SEEG_Steer_New_Widget.h"
#include "ui_BCI_SEEG_Steer_New_Widget.h"BCI_SEEG_Steer_New_Widget::BCI_SEEG_Steer_New_Widget(QWidget *parent) :QWidget(parent),ui(new Ui::BCI_SEEG_Steer_New_Widget)
{ui->setupUi(this);setWindowFlags(Qt::FramelessWindowHint);showMaximized();//初始化時先告訴widget,是最大化的狀態
}BCI_SEEG_Steer_New_Widget::~BCI_SEEG_Steer_New_Widget()
{delete ui;
}//重寫鼠標按下事件
void BCI_SEEG_Steer_New_Widget::mousePressEvent(QMouseEvent *event)
{///< 判斷是否點擊了自定義標題欄,我的ui中標題欄名字叫【title_frame】,使用時要改成你的控件,你希望鼠標在哪個區域按下時,觸發可移動的事件,就改成哪個控件的名字if (event->button() == Qt::LeftButton &&childAt(event->pos()) && childAt(event->pos())->objectName() == "title_frame"){if (isMaximized()) {// 保存鼠標在屏幕中的絕對位置QPoint globalMousePos = event->globalPos();// 保存鼠標在最大化窗口中的相對位置比例qreal xRatio = (qreal)event->pos().x() / width();qreal yRatio = (qreal)event->pos().y() / height();// 恢復普通窗口并調整大小showNormal();resize(1344, 756);ui->btn_max->setIcon(QIcon(":/img/maximize windows.svg"));// 計算鼠標在新窗口中的預期位置int newX = xRatio * width();int newY = yRatio * height();// 計算窗口應該移動到的位置,使鼠標保持在同一屏幕位置QPoint newWindowPos = globalMousePos - QPoint(newX, newY);// 確保窗口不會移出屏幕QRect screenGeometry = QApplication::desktop()->availableGeometry(this);newWindowPos.setX(qMax(screenGeometry.left(),qMin(newWindowPos.x(),screenGeometry.right() - width())));newWindowPos.setY(qMax(screenGeometry.top(),qMin(newWindowPos.y(),screenGeometry.bottom() - height())));// 移動窗口到新位置move(newWindowPos);// 更新拖動位置為鼠標在窗口中的新位置m_dragPosition = QPoint(newX, newY);}else {// 普通窗口狀態下直接計算偏移m_dragPosition = event->globalPos() - frameGeometry().topLeft();}m_isDragging = true;event->accept();return;}QWidget::mousePressEvent(event);
}//重寫鼠標移動事件
void BCI_SEEG_Steer_New_Widget::mouseMoveEvent(QMouseEvent *event)
{///< 處理窗口拖動if (m_isDragging && (event->buttons() & Qt::LeftButton)) {move(event->globalPos() - m_dragPosition);event->accept();return;}QWidget::mouseMoveEvent(event);
}//重寫鼠標釋放事件
void BCI_SEEG_Steer_New_Widget::mouseReleaseEvent(QMouseEvent *event)
{Q_UNUSED(event);m_isDragging = false;
}//點擊最小化按鈕
void BCI_SEEG_Steer_New_Widget::on_btn_mini_released()
{showMinimized();
}//點擊最大化/normal按鈕
void BCI_SEEG_Steer_New_Widget::on_btn_max_released()
{if (isMaximized()) {showNormal();this->resize(1344, 756);ui->btn_max->setIcon(QIcon(":/img/maximize windows.svg"));} else {showMaximized();this->resize(1920, 1080);ui->btn_max->setIcon(QIcon(":/img/restored windows.svg"));}
}//點擊關閉按鈕
void BCI_SEEG_Steer_New_Widget::on_btn_close_released()
{this->close();
}
.ui文件
ui界面代碼我就不附上了,相關的只有標題欄和3個按鈕而已,布局如下
--END--