窗口跟着鼠标移动
1.重写鼠标按下事件,记录鼠标在窗口中的相对位置
2.重写鼠标移动事件,调用move方法使得窗口移动到鼠标的位置(调用globalPos方法获取鼠标的位置)
3.注意点:移动时鼠标的位置还要减去一开始的相对位置,否则,窗口直接就是左上角跟着鼠标移动了,没有保持最开始鼠标和窗口的相对位置
如下,鼠标位置没有减去相对位置,就会出现下面的情况:
拖动标题栏窗口恢复
1.鼠标按下事件中记录是否是在标题栏按下
2.鼠标移动事件中,如果是在标题栏按下,那么窗口恢复,同时记录窗口最大化时的宽度,以及用一个标记变量记录窗口从最大化恢复到了正常状态
3.如果窗口是正常状态,那么窗口跟着鼠标移动,注意此时要更新前面记录的那个相对位置的值,既然窗口从最大化变为了正常,那么我一开始在窗口按下的相对位置也要进行同比例的变化。
如果不变化就会出现下面的情况:
完整代码如下:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include<QLabel>
#include<QPushButton>
#include<QMouseEvent>
#include<QHBoxLayout>
#include<QBoxLayout>
#include<QApplication>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr):QWidget(parent){//去掉自带的标题栏setWindowFlag(Qt::FramelessWindowHint);setStyleSheet(R"(font-family:"Microsot YaHei";font-size:12px)");//整个窗口垂直布局QVBoxLayout* v_box=new QVBoxLayout(this);v_box->setContentsMargins(0,0,0,0);v_box->setSpacing(0);//创建标题栏title_bar=new QWidget(this);title_bar->setFixedHeight(60);title_bar->setStyleSheet(R"(.QWidget{background-color:#edf5f9})");//标题栏水平布局QHBoxLayout* h_box=new QHBoxLayout(title_bar);h_box->setContentsMargins(0,0,0,0);h_box->setSpacing(0);//创建窗口标题window_title=new QLabel(this);window_title->setText("自定义标题栏");window_title->setAlignment(Qt::AlignLeft|Qt::AlignVCenter);h_box->addWidget(window_title);//创建最大化按钮btn_max=new QPushButton(this);btn_max->setFixedSize(100,50);btn_max->setText("点我最大化");h_box->addWidget(btn_max);//创建窗口主体body=new QWidget(this);body->setStyleSheet("background-color:gray");v_box->addWidget(title_bar);v_box->addWidget(body);resize(700,500);//绑定槽函数,最大化窗口connect(btn_max,&QPushButton::clicked,this,[=](){//窗口为正常状态if(windowState().testFlag(Qt::WindowNoState)){//则点击后变为最大this->setWindowState(Qt::WindowMaximized);btn_max->setText("点我恢复");}else if(windowState().testFlag(Qt::WindowMaximized)){//窗口为最大化,点击则恢复正常this->setWindowState(Qt::WindowNoState);btn_max->setText("点我最大化");}});}~Widget()=default;protected://实现鼠标拖动窗口移动//实现最大化窗口时,在标题栏按下,然后拖动,窗口恢复原来的大小void mousePressEvent(QMouseEvent* ev){//记录鼠标在窗口中的相对位置press_pos=ev->pos();QPoint global_press_pos=ev->globalPos();if(title_bar==QApplication::widgetAt(global_press_pos)||window_title==QApplication::widgetAt(global_press_pos)){//记录按下的位置是标题栏press_in_title=true;}}void mouseMoveEvent(QMouseEvent* ev){//鼠标按下后拖动,如果此时窗口时最大状态,且是在标题栏按下if(windowState().testFlag(Qt::WindowMaximized)&&press_in_title){//记录窗口最大化时的宽度width_of_max=width();//那么窗口恢复正常setWindowState(Qt::WindowNoState);btn_max->setText("点我最大化");//标记一下窗口从最大变为正常了max_to_normal=true;//需要注意的的是窗口恢复正常后,width()方法获取的宽度不会立即更新}//正常状态下,鼠标拖动窗口移动if(windowState().testFlag(Qt::WindowNoState)){//获取窗口当前的宽度int width_of_now=width();if(max_to_normal &&width_of_now!=width_of_max){//如果窗口从最大化变为了正常,且窗口前后宽度不相等//此时就需要更新press_pos的值//来保持恢复正常之后,鼠标在窗口的位置,仍然是刚按下时,鼠标在窗口的位置//那么最开始按下的相对位置也要等比例缩小//算出比值,正常状态下的宽度比上最大化时的宽度float ratio=width_of_now/(float)width_of_max;press_pos*=ratio;//标记变量复原max_to_normal=false;}//正常状态下,鼠标移动,窗口跟着移动,则需要减去最开始的相对位置。//否则就会是窗口的左上角跟着鼠标移动this->move(ev->globalPos()-press_pos);}}void mouseReleaseEvent(QMouseEvent* ev){//鼠标释放后标记变量复原press_in_title=false;}private:bool press_in_title=false;//记录是否在标题栏按下bool max_to_normal=false;//记录窗口从最大变为正常int width_of_max;//记录窗口最大化下时的宽度QPoint press_pos;//记录鼠标按下时的在窗口中的位置QWidget* title_bar;//标题栏QLabel* window_title;//窗口标题QPushButton* btn_max;//最大化按钮QWidget* body;//窗口主体区
};
#endif // WIDGET_H
正确效果如下:
学习链接:https://github.com/0voice