16. Qt系统相关:事件、定时器
1. Qt事件
1.1 简介
事件是应用程序内部或者外部产生的事情或者动作的统称。在Qt中使用一个对象来表示一个事件。所有的Qt事件均继承于抽象类QEvent。事件是由系统或者Qt平台本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件是在用户操作时发出,如键盘事件、鼠标事件等,另一些则是由系统本身自动发出,如定时器事件。常见的Qt事件如下:
常见事件描述:
1.2 事件处理
事件处理一般常用的方法为:重写相关的Event函数。
在Qt中,几乎所有的Event函数都是虚函数,所以可以重新实现。比如鼠标的进入和离开事件,通过重写enterEvent()和leaveEvent()函数实现。
1.3 鼠标事件
1.3.1 鼠标进入&离开事件
继承实现鼠标进入、离开事件函数:
virtual void enterEvent(QEnterEvent *event);
virtual void leaveEvent(QEvent *event);
例如我们需要获取某个控件的鼠标进入、离开事件,就可以继承对应的控件类,实现enterEvent、leaveEvent接口,实现我们自定义的事件处理操作。
在ui界面上,右键对应的控件,通过提升操作,将其提升为我们实现的类,即可快速实现界面控件替换为我们实现的控件类。
1.3.2 鼠标点击事件
virtual void mousePressEvent(QMouseEvent *event)
注意:鼠标上左键、右键、鼠标滚轮按下、前进/后退侧键,都能触发mousePressEvent事件
(1)获取鼠标点击时坐标
- 坐标原点为当前控件左上角:
inline int QMouseEvent::x() const
inline int QMouseEvent::y() const
- 坐标原点为整个屏幕左上角:
inline int QMouseEvent::globalX() const
inline int QMouseEvent::globalY() const
(2)获取触发该事件的按键类型
inline Qt::MouseButton button() const
1.3.3 鼠标释放事件
virtual void mouseReleaseEvent(QMouseEvent *event)
1.3.4 鼠标双击事件
virtual void mouseDoubleClickEvent(QMouseEvent *event)
注意:双击操作也会触发单击事件
1.3.5 鼠标移动事件
virtual void mouseMoveEvent(QMouseEvent *event)
注意:随意的鼠标移动,会触发大量的鼠标移动事件,如果多事件进行捕获、进行一些逻辑操作,可能导致程序卡顿等情况,所以Qt为了保证程序流畅性,默认不会开启鼠标移动事件追踪,也就是不会调用mouseMoveEvent接口。
开启鼠标移动事件追踪:
inline void QWidget::setMouseTracking(bool enable)
1.3.6 鼠标滚轮事件
virtual void QWidget::wheelEvent(QWheelEvent *event)
获取滚轮滚动信息:
inline QPoint angleDelta() const
获取滚轮滚动长度(正负表示方向):
1.4 键盘事件
Qt中的按键事件是通过QKeyEvent类来实现的,当键盘上的按键被按下或者释放时,键盘事件便会触发。
注意:只有当控件获取到焦点时,该控件的键盘事件才会被触发。
1.4.1 单个按键
virtual void keyPressEvent(QKeyEvent *event);
1.4.2 组合按键
Qt::KeyboardModifier 中定义了在处理键盘事件时对应的修改键。在 Qt 中,键盘事件可以与修改键⼀起使⽤,以实现⼀些复杂的交互操作。KeyboardModifier 中修改键的具体描述如下:
示例:判断是否按下ctrl+A组合键
1.5 窗口事件
1.5.1 窗口移动事件
virtual void moveEvent(QMoveEvent *event);
QMoveEvent核心接口:
inline const QPoint &pos() const { return m_pos; }
inline const QPoint &oldPos() const { return m_oldPos;}
1.5.2 窗口大小改变事件
virtual void resizeEvent(QResizeEvent *event);
QResizeEvent核心接口:
inline const QSize &size() const { return m_size; }
inline const QSize &oldSize()const { return m_oldSize;}
2. Qt定时器
Qt 中在进⾏窗⼝程序的处理过程中,经常要周期性的执⾏某些操作,或者制作⼀些动画效果,使⽤定 时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执⾏某⼀个任务。定时器在很多场景下都会 使⽤到,如弹窗⾃动关闭之类的功能等。
Qt中的定时器分为 QTimerEvent 和 QTimer 这2个类。
• QTimerEvent类 用来描述⼀个定时器事件。在使⽤时需要通过 startTimer() 函数来开启⼀个定时
器,这个函数需要输⼊⼀个以毫秒为单位的整数作为参数来表明设定的时间,它返回的整型值代表
这个定时器。当定时器溢出时(即定时时间到达)就可以在 timerEvent() 函数中获取该定时器的
编号来进⾏相关操作。
• QTimer类 来实现⼀个定时器,它提供了更⾼层次的编程接⼝,如:可以使⽤信号和槽,还可以设置只运⾏⼀次的定时器。
2.1 QTimerEvent
QTimerEvent继承自QEvent,QObject提供了事件的接收和派发,可以直接实现QObject的
void timerEvent(QTimerEvent *event)
接口,来接收并处理TimerEvent事件。
QObject中也实现了创建开始定时器和关闭定时器的接口,方便快速实现定时器效果:
int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer);
int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer);
void killTimer(int id);
注意:一个程序内多个定时器都会触发TimerEven事件,所以需要TimerId来标识某一个定时器,在事件处理接口中,通过QTimerEvent的timerId()接口获取触发本次事件的定时器id。
2.2 QTimer
QTimer可以让我们更加方便快速的实现定时器效果,并利用信号槽机制来处理timeout事件。
3. 事件分发器
在Qt中,事件分发器(Event Dispatcher)是一个核心概念,用于处理GUI应用程序中的事件。事件分发器负责将事件从一个对象传递到另一个对象,直到事件被处理或取消。
每个继承自QObject类 或 QObject本身都可以在本类中重写bool event(QEvent *event)函数,来实现相关事件的捕获和拦截。
3.1 事件分发器工作原理
在Qt中,我们发生的事件就是传递给了QObject对象,更具体点是传递给了QObject对象的event函数。所有的事件都会进入到这个函数里面,所以我们处理事件就要重写该函数。event函数本身不会处理事件,而是根据事件类型(type值)调用不同的事件处理函数。事件分发器就是工作在应用程序向下分发事件的过程:
在事件分发的过程中,事件分发器也可以做拦截操作。通过bool event(QEvent *e)函数,其返回值为true表示拦截,不向下分发。
4. 事件过滤器
在 Qt 中,⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等。
通过重写bool event(QEvent *e)函数利用事件分发器的原理,可以实现事件拦截,但是如果组件很多就需要重写很多event函数,非常麻烦,并且很可能导致其他问题。
Qt提供了外⼀种机制来达到这⼀⽬的:事件过滤器。 事件过滤器是在应⽤程序分发到 event事件分发器 之前,再做⼀次更⾼级的拦截。如下图⽰:
4.1 事件过滤器使用
(1)安装事件过滤器
安装接口:void installEventFilter(QObject *filterObj);
控件调用installEventFilter安装事件过滤器后,发送给该控件的所有事件会先发送给它安装的过滤器filterObj,由filterObj中的eventfilter接口处理,如果eventfilter返回true,则事件被过滤,不会再发送给该控件。
(2)重写事件过滤器函数:eventfilter()
virtual bool eventfilter(QObject *watched, QEvent *event);