一、简介

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

二、Qt中的事件

事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的通称。Qt中使用一个对象来表示一个事件,继承自QEvent类。需要说明的是,事件与信号并不相同,比如单击一下界面上的按钮,那么就会产生鼠标事件 QMou­seEvent (不是按钮产生的 ),而因为按钮被按下了 ,所以它会发出 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中的事件处理与传递的更多相关文章

  1. 第39课 Qt中的事件处理(下)

    1. 事件的传递过程 (1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序 (2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject: ...

  2. 第38课 Qt中的事件处理(上)

    1. GUI程序原理回顾 (1)图形界面应用程序的消息处理模型 (2)思考:操作系统发送的消息如何转变为Qt信号 2. Qt中的事件处理 (1)Qt平台将系统产生的消息转换为Qt事件 ①Qt事件是一个 ...

  3. Qt 中的事件处理(二)

    1. 回顾事件传递的过程 ①源头:操作系统   操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中, ②应用程序收到系统消息后, 他会将系统消息翻译成对应的 ...

  4. Qt 中的事件处理(一)

    1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的 系统内核的消息通过事件处理转变成QT的信号 2. Qt中 ...

  5. Qt事件系统基本概念

    (转自:http://www.cnblogs.com/andy1987/p/3322059.html) 1. QT事件系统 Qt应用程序的消息处理是基于事件驱动的,程序的每个动作都是由某个事件所触发的 ...

  6. QT事件过滤器(QT事件处理的5个层次:自己覆盖或过滤,父窗口过滤,Application过滤与通知)

    Qt事件模型一个真正强大的特色是一个QObject 的实例能够管理另一个QObject 实例的事件. 让我们试着设想已经有了一个CustomerInfoDialog的小部件.CustomerInfoD ...

  7. Qt 事件系统浅析 (用 Windows API 描述,分析了QCoreApplication::exec()和QEventLoop::exec的源码)(比起新号槽,事件机制是更高级的抽象,拥有更多特性,比如 accept/ignore,filter,还是实现状态机等高级 API 的基础)

    事件系统在 Qt 中扮演了十分重要的角色,不仅 GUI 的方方面面需要使用到事件系统,Signals/Slots 技术也离不开事件系统(多线程间).我们本文中暂且不描述 GUI 中的一些特殊情况,来说 ...

  8. Qt事件系统之二:鼠标事件和滚轮事件

    在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图 ...

  9. Qt线程(2) QThread中使用WorkObject

    一般继承QThread的WorkThread都会在重载的run()中创建临时的WorkObject,这样能确定这个WorkObject在该thread中使用 那如果这个WorkObject是个Sing ...

随机推荐

  1. Matlab遗传算法优化问题求解的演示样例代码

    代码例如以下: function m_main() clear clc Max_gen = 100;% 执行代数 pop_size = 100;%种群大小 chromsome = 10;%染色体的长度 ...

  2. Axure使用笔记

    软件设置类 两个矩形的双边框,边框重合: 项目---项目设置---边界对齐---内边界对齐. 自动备份时间设置 文件-自动备份设置-默认15分钟,根据电脑硬件可以调整. Axure 8 可以不用安装 ...

  3. OpenGL在MFC中的使用总结(一)——基本框架

    项目中要画3D显示的模型,于是要用到OpenGL,加上是在MFC中,并且是在MFC中的ActiveX中使用.再并且鉴于他们程序主框架的设定.常规的方法还不一定能实现.所以还是查过不少资料,在此一一总结 ...

  4. Spring嵌套事务控制

    A类   callBack_test() B类   testadd() C类   select(),得查询到B类testadd方法中新增的数据.以及初始化一些属性 场景:A类 嵌套 B类  B类嵌套C ...

  5. 2016/3/10 PHP环境搭建 LAMP WAMP

    1. php成为服务器端的脚本语言.弱类型语言.$ JavaScript是弱类型语言.var Java强类型语言.byte short int long double float boolean 2. ...

  6. 查源码分析 游标 写 需要 cursors 一切不看源码的代码引入都是定时炸弹的启动

    https://github.com/PyMySQL/PyMySQL/blob/master/pymysql/__init__.py 建立连接 def Connect(*args, **kwargs) ...

  7. ABAP 创建和调用WebService

    1.创建WebService ① SE37创建RFC函数 ② SE80创建企业服务-service provider-existing ABAP object 或SE37-实用程序-创建Web服务 ③ ...

  8. forword 与 redirect

    直接转发方式(Forward) 客户端和浏览器只发出一次请求,Servlet.HTML.JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于每个信息资源是共享的 ...

  9. sabaki and leelazero

    https://tieba.baidu.com/p/5462772621?see_lz=1 http://zero.sjeng.org/ https://www.jianshu.com/p/a4ba1 ...

  10. android 设置textview中划线效果

    textView.getPaint().setFlags(Paint. UNDERLINE_TEXT_FLAG ); //下划线   textView.getPaint().setAntiAlias( ...