第三章Qt事件系统
文章目录
1.事件系统
在Qt中,事件是派生抽象QEvent类的对象,它表示应用程序内发生的事情,或应用程序需要知道的外部活动的结果。事件可以由QObject子类的任何实例接收和处理。
Qt程序需要在main函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始Qt的事件循环。执行后,程序将进入事件循环来监听应用程序的事件,当事件发生时,Qt将创建一个事件对象。
事件是如何传递的
通过
QCoreApplication::sendEvent()
发送事件 用户触发事件 操作系统接收 将事件分发给对应的应用程序 应用程序事件过滤器处理
nativeEventFilter() 通过
QCoreApplication::postEvent()
发送事件 事件队列 事件分发给对应控件
QApplication::notify() 控件事件过滤处理
QObject::eventFilter() 将事件进行分发
QObject::event() 控件处理
例如mousePressEvent() 忽略该事件 控件的父级处理
事件类型
c
#include <QWidget>
#include <QMouseEvent>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
//鼠标事件
void mouseDoubleClickEvent(QMouseEvent *)override;
void mousePressEvent(QMouseEvent *)override;
void mouseReleaseEvent(QMouseEvent *)override;
void mouseMoveEvent(QMouseEvent *)override;
//按键事件
void keyPressEvent(QKeyEvent *)override;
void keyReleaseEvent(QKeyEvent * )override;
//窗口事件
void closeEvent(QCloseEvent *) override;
void hideEvent(QHideEvent *)override;
void resizeEvent(QResizeEvent *)override;
//焦点事件
void focusInEvent(QFocusEvent*)override;
void focusOutEvent(QFocusEvent*)override ;
void contextMenuEvent(QContextMenuEvent*)override;
//程序状态改变事件
void changeEvent(QEvent*)override;
//定时器事件
void timerEvent(QTimerEvent*)override;
};
事件处理
c
#include "Widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
this->setMouseTracking(false);//启用鼠标追踪
this->setFocus();
new QPushButton("按钮",this);
this->startTimer(10);//10毫秒
}
Widget::~Widget() {}
void Widget::mouseDoubleClickEvent(QMouseEvent *)
{
qInfo()<<"鼠标双击";
}
void Widget::mousePressEvent(QMouseEvent *)
{
qInfo()<<"鼠标按下";
}
void Widget::mouseReleaseEvent(QMouseEvent *)
{
qInfo()<<"鼠标释放";
}
void Widget::mouseMoveEvent(QMouseEvent *)
{
static int16_t i=0;
qInfo()<<"鼠标移动"<<i++;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
qInfo()<<event->text()<<"按键已按下";
}
void Widget::keyReleaseEvent(QKeyEvent *event)
{
auto k=event->key();
qInfo()<<k<<"按键已弹起";
}
void Widget::closeEvent(QCloseEvent *)
{
qInfo()<<"窗口关闭";
}
void Widget::hideEvent(QHideEvent *)
{
qInfo()<<"窗口隐藏";
}
void Widget::resizeEvent(QResizeEvent *)
{
qInfo()<<"窗口大小改变";
}
void Widget::focusInEvent(QFocusEvent *)
{
qInfo("有焦点");
}
void Widget::focusOutEvent(QFocusEvent *)
{
qInfo("失去焦点");
}
void Widget::contextMenuEvent(QContextMenuEvent *)
{
qInfo()<<"收到信号,弹出菜单";
}
void Widget::changeEvent(QEvent *e)
{
if(e->type()==QEvent::WindowStateChange)
qInfo()<<"发生改变";
}
void Widget::timerEvent(QTimerEvent *)
{
static qint32 x=0,y = 0;
this->move(x++%600+500,y++%800);
}
c
bool event(QEvent *event) override;
bool Widget::event(QEvent *event)
{
if(event->type()==QEvent::Type::MouseButtonPress)
return true;//屏蔽了MouseButtonPress事件
return QWidget::event(event); //把事件交给父类处理
}
发送事件
- 自定义事件
c
#include <QWidget>
#include <QMouseEvent>
#include <QEvent>
class MyCustomEvent:public QEvent
{
public:
MyCustomEvent():QEvent(QEvent::Type::User)
{
info = "自定义事件";
}
QString getMessage()
{
return info;
}
private:
QString info;
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
protected:
//鼠标事件
void mousePressEvent(QMouseEvent *)override;
//自定义事件
void customEvent(QEvent *event)override;
};
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(640,480);
}
void Widget::mousePressEvent(QMouseEvent *)
{
qInfo()<<"鼠标按下";
MyCustomEvent* ce = new MyCustomEvent;
qApp->sendEvent(this,ce);
}
void Widget::customEvent(QEvent *event)
{
if(event->type()==QEvent::User)
{
auto ce = dynamic_cast<MyCustomEvent*>(event);
if(!ce)
return;
qInfo()<<ce->getMessage();
}
}
- sendEvent和postEvent的区别
sendEvent 事件发送后,事件不会被删除,是分配在栈上的
postEvent 事件必须在堆上分配,事件发布后会被删除,事件按优先级降序排列。
2.事件传播机制
事件接受和忽略
QEvent()有accept()和ignore()函数
accept,本组处理该事件,不会被传递
ignore,不处理,交给父处理
事件分发
事件过滤
用事件过滤器实现鼠标拖动无边框窗口案例
c
#include <QWidget>
#include <QMouseEvent>
#include <QEvent>
#include <QPushButton>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
//事件过滤处理器
bool eventFilter(QObject *watched, QEvent *event)override;
private:
QPoint pressPos;
#include "Widget.h"
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(640,480);
setWindowFlag(Qt::FramelessWindowHint);//设置无边框
installEventFilter(this);//在对象上安装事件过滤器,如果不装,过滤器重写无效
}
Widget::~Widget() {}
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
if(watched==this)
{
if(event->type()==QEvent::MouseButtonPress)
{
auto me=dynamic_cast<QMouseEvent*>(event);
pressPos = me->pos();
return true;
}
else if(event->type()==QEvent::MouseMove)
{
auto me=dynamic_cast<QMouseEvent*>(event);
move(me->globalPosition().toPoint()-pressPos);
//globalPosition是鼠标在全局的位置,pressPos是鼠标相对于窗口左上角的位置,两者一减,就是窗口左上角在全局的位置
}
else
return false;
}
else
return QObject::eventFilter(watched,event);
}
};
3.事件和信号的区别
事件 | 信号 | |
---|---|---|
与QObject的关系 | 由具体对象进行处理 | 由具体对象主动产生 |
对程序的影响 | 改写事件处理函数可能导致程序行为发生改变 | 信号是否存在对应的槽函数不会改变程序的行为 |
两者的联系 | 一般而言,信号在具体的事件处理函数中产生 |
信号和事件是两个不同层面的东西,发出者不同,作用不同。