三种方法实现qt无边框窗口移动
方法一:
通过鼠标点击事件和鼠标移动事件来实现无边框窗口的移动。
#include <QApplication>
#include<QWidget>
#include<QEvent>
#include<QMouseEvent>
class Widget:public QWidget
{
public:
Widget(QWidget* parent=nullptr):QWidget(parent)
{
this->resize(640,480);
this->setWindowFlag(Qt::FramelessWindowHint,true);//设置窗口无边框
}
~Widget()
{
}
protected:
//鼠标点击事件
void mousePressEvent(QMouseEvent* ev)override
{
if(ev->button()==Qt::LeftButton)//这里判断,是否是鼠标左键按下,只有左键按下窗口才能移动
{
pos=ev->pos();//用成员变量记录下按下左键时鼠标的坐标
}
}
//鼠标移动事件
void mouseMoveEvent(QMouseEvent*ev)override
{
if(ev->buttons()==Qt::LeftButton)//注意,这里用的是buttons,因为buttons里存储了之前的按键信息
{
int x,y;
x=ev->pos().x()-pos.x();
y=ev->pos().y()-pos.y();
this->move(this->x()+x,this->y()+y);
}
}
protected:
QPoint pos;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
方法二:
同过事件分发函数来处理。
在此之前我们要明白一点,就是事件分发函数,是处理所有事件的总函数,函数原型为 bool event(QEvent *ev); 返回值为bool类型,用于判断该事件是否完成,如果完成返回true,反之返回false.
这里我们主要通过时间的类型来判断,通过方法一我们得知,主要用到的事件就是mousePressEvent和mouseMoveEvent,所以这里我们就可以自定义这两个事件。
#include <QApplication>
#include<QWidget>
#include<QEvent>
#include<QMouseEvent>
class Widget:public QWidget
{
public:
Widget(QWidget* parent=nullptr):QWidget(parent)
{
this->resize(640,480);
this->setWindowFlag(Qt::FramelessWindowHint,true);//设置窗口无边框
}
~Widget()
{
}
protected:
bool event(QEvent* ev) override
{
switch (ev->type()) //这里更具事件的类型来判断,
{
case QEvent::Type::MouseButtonPress:
{
QMouseEvent* e=static_cast<QMouseEvent*>(ev);//因为后续要访问鼠标的按键类型和位置,而父类QEvent是没有这些成员的,所以要强转
if(e->button()==Qt::LeftButton)
{
pos=e->pos();//记录此时的鼠标左键点击位置
}
}
break;
case QEvent::Type::MouseMove:
{
QMouseEvent* e=static_cast<QMouseEvent*>(ev);//因为后续要访问鼠标的按键类型和位置,而父类QEvent是没有这些成员的,所以要强转
if(e->buttons()==Qt::LeftButton)
{
int x,y;
x=e->pos().x()-pos.x();
y=e->pos().y()-pos.y();
this->move(this->x()+x,this->y()+y);
}
}
break;
default:
break;
}
return QWidget::event(ev);//注意,因为event是事件分发的总函数,所以其他的事件仍然用父类中给我们定义好的event函数。
}
protected:
QPoint pos;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
方法三:
通过事件过滤器来处理无边框窗口的移动
首先我们要明白自定义事件的发送过程,当我们使用sendEvent或者是postEvent来发送我们自定义的事件的时候,并不是直接发送给对象的,而是有一个过程。
当我们发送自定义的事件时,首先是先通过QCoreApplication的notify函数来通知这个事件,之后由事件过滤器eventFilter(前提是有事件过滤器,如果没有则跳过此步骤)对该事件进行过滤,过滤后,再交给enent事件分发函数,最后在由分发函数来选选择由哪个事件处理函数来处理该事件。
所谓的事件过滤器,就是我们提前对传送来的事件进行我们自定义的处理
#include <QApplication>
#include<QWidget>
#include<QEvent>
#include<QMouseEvent>
class Widget:public QWidget
{
public:
Widget(QWidget* parent=nullptr):QWidget(parent)
{
this->resize(640,480);
this->setWindowFlag(Qt::FramelessWindowHint,true);//设置窗口无边框
//安装事件过滤器
installEventFilter(this);//根据我们自定义的事件过滤器所在的对象来填写,如我们重写的事件过滤器就是Widget的成员函数,所以填写this即可
}
~Widget()
{
}
protected:
//自定义事件过滤器
bool eventFilter(QObject *obj,QEvent* ev)override
{
if(ev->type()==QEvent::Type::MouseButtonPress)//判断是否有鼠标点击事件
{
QMouseEvent* e=static_cast<QMouseEvent*> (ev);
if(e->button()==Qt::LeftButton)//判断是否是左键点击
{
pos=e->pos();
}
}
else if(ev->type()==QEvent::Type::MouseMove)//判断是否有鼠标移动事件
{
QMouseEvent* e=static_cast<QMouseEvent*> (ev);
if(e->buttons()==Qt::LeftButton)//判断历史点击是否是左键点击
{
int x,y;
x=e->pos().x()-pos.x();
y=e->pos().y()-pos.y();
this->move(this->x()+x,this->y()+y);
}
}
}
protected:
QPoint pos;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
通过以上方法,我们不能发现,无边框移动的本质算法是一致的,只是我们有多种实现的方法,在实际开发中,我们也可以根据当时的实际情况来选择不同的方法。