窗口跟着鼠标移动
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_OBJECT
public:
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