Qt事件系统之一:Qt中的事件处理与传递
一、简介
在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent、鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图如下所示。本章会详细讲解这3个常见的事件,还会涉及事件过滤器、自定义事件和随机数的知识。关于本章的相关内容,可以在Qt帮助中通过The Event System 关键字查看。

二、Qt中的事件
事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。Qt中使用一个对象来表示一个事件,继承自QEvent类。需要说明的是,事件与信号并不相同,比如单击一下界面上的按钮,那么就会产生鼠标事件 QMouseEvent (不是按钮产生的 ),而因为按钮被按下了 ,所以它会发出 clicked() 单击信号(是按钮产生的)。这里一般只关心按钮的单击信号,而不用考虑鼠标事件,但是如果要设计一个按钮,或者当单击按钮时让它产生别的效果,那么就要关心鼠标事件了。可以看到,事件与信号是两个不同层面的东西,发出者不同,作用也不同。在Qt中,任何 QObject子类实例都可以接收和处理事件。
2.1 事件的处理
一个事件由一个特定的 QEvent 子类来表示,但是有时一个事件又包含多个事件类型,比如鼠标事件又可以分为鼠标按下、双击和移动等多种操作。这些事件类型都由 QEvent 类的枚举型 QEvent::Type 来表示,其中包含了 一百多种事件类型,可以在 QEvent 类的帮助文档中查看。虽然 QEvent 的子类可以表示一个事件,但是却不能用来处理事件,那么应该怎样来处理一个事件呢?在 QCoreApplication 类的notify()函数的帮助文档处给出了5种处理事件的方法:
方法一:重新实现部件的 paintEvent()、mousePressEvent() 等事件处理函数。这是最常用的一种方法,不过它只能用来处理特定部件的特定事件。
方法二:重新实现 notify() 函数。这个函数功能强大,提供了完全的控制,可以在事件过滤器得到事件之前就获得它们。但是,它一次只能处理一个事件。
方法三:向 QApplication 对象上安装事件过滤器。因为一个程序只有一个 QApplication 对象,所以这样实现的功能与使用 notify() 函数是相同的,优点是可以同时处理多个事件。
方法四:重新实现 event() 函数。QObject 类的 event() 函数可以在事件到达默认的事件处理函数之前获得该事件。
方法五:在对象上安装事件过滤器。使用事件过滤器可以在一个界面类中同时处理不同子部件的不同事件。
在实际编程中,最常用的是方法一,其次是方法五。因为方法二需要继承自 QApplication 类;而方法三要使用一个全局的事件过滤器,这将减缓事件的传递,所以,虽然这两种方法功能很强大,但是却很少被用到。
2.2 事件的传递
在每个程序的 main() 函数的最后都会调用 QApplication 类的 exec() 函数,它会使Qt应用程序进人事件循环,这样就可以使应用程序在运行时接收发生的各种事件。一旦有事件发生,Qt 便会构建一个相应的 QEvent 子类的对象来表示,然后将它传递给相应的 QObject 对象或其子对象。下面通过例子来看一下Qt中的事件传递过程。
新建Qt Gui应用,项目名称为myEvent,基类选择QWidget,然后类名保持 Widget 不变。建立完成后向项目中添加新文件,模板选择C+ +类,类名为MyLineEdit,基类手动填写为QLineEdit,自定义了一个MyLineEdit 类。
mylineEdit. h 文件:
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr);
//event()函数获取事件的类型
bool event(QEvent *event);
protected:
//MyLineEdit类的键盘按下事件
void keyPressEvent(QKeyEvent *event);
};
#endif // MYLINEEDIT_H
这里添加了keyPressEvent()函数和event()函数的声明。
mylineEdit. cpp 文件:
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
MyLineEdit::MyLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
// MyLineEdit类的键盘按下事件
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("MyLineEdit键盘按下事件");
//让MyLineEdit输入栏能输入字符
QLineEdit::keyPressEvent(event); // 执行QLineEdit类的默认事件处理
event->ignore(); // 忽略该事件
}
//event()函数获取事件的类型
bool MyLineEdit::event(QEvent *event)
{
//判断触发事件类型是否为键盘按下事件
if(event->type() == QEvent::KeyPress)
qDebug() << tr("MyLineEdit的event()函数");
return QLineEdit::event(event); // 执行QLineEdit类event()函数的默认操作
}
这里自定义了一个MyLineEdit类,它继承自QWidget,并且实现了MyLineEdit类的keyPressEvent()函数和event()函数。event()函数中使用了 event->type() 来获取事件的类型。如果是键盘按下事件 QEvent::KeyPress,则输出信息,另外返回父类的event()函数的操作结果。
widget.h 文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class MyLineEdit;
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
// Widget类的事件过滤器
bool eventFilter(QObject *obj, QEvent *event);
private:
Ui::Widget *ui;
MyLineEdit *lineEdit;
protected:
// Widget类的键盘按下事件
void keyPressEvent(QKeyEvent *event);
};
#endif // WIDGET_H
这里也添加了keyPressEvent()函数的声明。
widget.cpp 文件:
#include "widget.h"
#include "ui_widget.h"
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
lineEdit = new MyLineEdit(this);
lineEdit->move(100, 100);
}
Widget::~Widget()
{
delete ui;
}
// Widget类的键盘按下事件
void Widget::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("Widget键盘按下事件");
}
// Widget类的事件过滤器
bool Widget::eventFilter(QObject *obj, QEvent *event) // 事件过滤器
{
// 如果是lineEdit部件上的事件
if(obj == lineEdit)
{
if(event->type() == QEvent::KeyPress)
qDebug() << tr("Widget的事件过滤器");
}
return QWidget::eventFilter(obj, event);
}
这里也实现了Widget类的keyPressEvent()函数,并且会调用MyLineEdit类的keyPressEvent()函数。在事件过滤器中,先判断该事件的对象是不是lineEdit,如果是,再判断事件类型,最后返回QWidget类默认的事件过滤器的执行结果。
运行程序,然后按下键盘的任意键,比如这里按下a键,执行结果如下图所示。

可以看到,事件的传递顺序是这样的:先是事件过滤器,然后是焦点部件的event()函数,最后是焦点部件的事件处理函数,例如这里的键盘按下事件函数;如果焦点部件忽略了该事件,那么会执行父部件的事件处理函数,该部件的函数,最后是该部件的事件处理函数,如上图所示。注意,event()函数和事件处理函数,是在该部件内进行重新定义的,而事件过滤器却是在该部件的父部件中进行定义的。

Qt事件系统之一:Qt中的事件处理与传递的更多相关文章
- 第39课 Qt中的事件处理(下)
1. 事件的传递过程 (1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序 (2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject: ...
- 第38课 Qt中的事件处理(上)
1. GUI程序原理回顾 (1)图形界面应用程序的消息处理模型 (2)思考:操作系统发送的消息如何转变为Qt信号 2. Qt中的事件处理 (1)Qt平台将系统产生的消息转换为Qt事件 ①Qt事件是一个 ...
- Qt 中的事件处理(二)
1. 回顾事件传递的过程 ①源头:操作系统 操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中, ②应用程序收到系统消息后, 他会将系统消息翻译成对应的 ...
- Qt 中的事件处理(一)
1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的 系统内核的消息通过事件处理转变成QT的信号 2. Qt中 ...
- Qt事件系统基本概念
(转自:http://www.cnblogs.com/andy1987/p/3322059.html) 1. QT事件系统 Qt应用程序的消息处理是基于事件驱动的,程序的每个动作都是由某个事件所触发的 ...
- QT事件过滤器(QT事件处理的5个层次:自己覆盖或过滤,父窗口过滤,Application过滤与通知)
Qt事件模型一个真正强大的特色是一个QObject 的实例能够管理另一个QObject 实例的事件. 让我们试着设想已经有了一个CustomerInfoDialog的小部件.CustomerInfoD ...
- Qt 事件系统浅析 (用 Windows API 描述,分析了QCoreApplication::exec()和QEventLoop::exec的源码)(比起新号槽,事件机制是更高级的抽象,拥有更多特性,比如 accept/ignore,filter,还是实现状态机等高级 API 的基础)
事件系统在 Qt 中扮演了十分重要的角色,不仅 GUI 的方方面面需要使用到事件系统,Signals/Slots 技术也离不开事件系统(多线程间).我们本文中暂且不描述 GUI 中的一些特殊情况,来说 ...
- Qt事件系统之二:鼠标事件和滚轮事件
在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图 ...
- Qt线程(2) QThread中使用WorkObject
一般继承QThread的WorkThread都会在重载的run()中创建临时的WorkObject,这样能确定这个WorkObject在该thread中使用 那如果这个WorkObject是个Sing ...
随机推荐
- ArcGIS Engine 中的多线程使用
转自原文ArcGIS Engine 中的多线程使用 一直都想写写AE中多线程的使用,但一直苦于没有时间,终于在中秋假期闲了下来.呵呵,闲话不说了,进入正题! 大家都了解到ArcGIS中处理大数据量时速 ...
- html5开发手机打电话发短信功能
原文:http://www.open-open.com/code/view/1449843459332 在很多的手机网站上,有打电话和发短信的功能,对于这些功能是如何实现的呢.其实不难,今天我们就用h ...
- iOS国际化:NSLocalizedString的使用
因为iOS和XCode版本号更新得太快的原因,导致网上非常多文章都失去了时效性,或许再过两三个月我这篇文章也将走上这条路,但起码能够让现阶段看到的人对iOS的国际化有个比較清楚的认识. NSLocal ...
- setenv LD_LIBRARY_PATH
For most Linux binaries, NCL was built using gcc and gfortran. This may cause a dependency on a file ...
- 找中位数O(n)算法
题目描写叙述: 给定一个未排序的整数数组,找到当中位数. 中位数是排序后数组的中间值,假设数组的个数是偶数个.则返回排序后数组的第N/2个数. 例子 给出数组[4, 5, 1, 2, 3], 返回 3 ...
- Sql sever 分组排序
维护人事的时候人事局要求加入一个新功能,详细需求例如以下:加入的人员在同一个单位的依照顺序编号而且单位也要实现时间排序,也就是说有两个排序,第一单位名称排序.先创建的一直在前.然后依照创建时间依次排序 ...
- 深度学习笔记之CNN(卷积神经网络)基础
不多说,直接上干货! 卷积神经网络(ConvolutionalNeural Networks,简称CNN)提出于20世纪60年代,由Hubel和Wiesel在研究猫脑皮层中用于局部敏感和方向选择的神经 ...
- 在CentOS上把Nginx从1.2.4升级到1.6.0
在CentOS上升级把Nginx从1.2.4升级到1.6.0 摘要:本文记录了在CentOS 6.3上,把Nginx从1.2.4升级到1.6.0的过程. 1. 概述 在我做的一个项目中,最近我对生产服 ...
- Python爬虫开发【第1篇】【多线程爬虫及案例】
糗事百科爬虫实例: 地址:http://www.qiushibaike.com/8hr/page/1 需求: 使用requests获取页面信息,用XPath / re 做数据提取 获取每个帖子里的用户 ...
- 杭电 1150 moving tables
http://acm.hdu.edu.cn/showproblem.php? pid=1050 Moving Tables Time Limit: 2000/1000 MS (Java/Others) ...