目录
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_OBJECT
public:
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--