1         QT事件系统

1.1  事件的定义

QT中事件是有专门的类QEvent,常见的有键盘事件QKeyEvent、鼠标事件QMouseEvent和定时器事件QTimerEvent。例如用鼠标单击下按钮,就会产生一个鼠标事件,按钮会产生一个单击信号。事件可以理解为发出信号的来源,信号的生产者,有了这个鼠标事件产生了这个单击信号。

1.2  事件和信号的区别

仔细来看,事件与信号其实并无多大差别,都是通过触发和响应函数来处理用户的请求。主要区别如下:

(1)    接收者不同

信号的接收者是槽,事件的接收者是一个队列,事件发生时,会产生一个事件对象被插入队列的尾部,系统会循环从队列的头部取事件对象进行处理。事件处理可以是异步的,信号的处理则是同步的。

(2)    单线和多线性

一个信号触发后,可以关联多个槽,多个槽会被执行,当然一个信号也可以触发另外一个信号。而事件则是与窗口相关的,所以事件回调时都是从当前窗口开始,一级一级向上派发,直到有一个窗口返回true,截断了事件的处理为止。

(3)    返回值作用

事件处理函数如果返回true,则这个事件处理已完成,QApplication会接着处理下一个事件,而如果返回false,那么事件分派函数会继续向上寻找下一个可以处理该事件的注册方法。信号处理函数的返回值对信号分派器来说是无意义的。

1.3  事件的接收和处理方法

1.3.1            事件传递逻辑

QT中事件的接收流程如下图所示,postEvent会将事件插入事件队列,异步处理事件,sendEvent直接将事件发出进行处理。如果返回TRUE或者调用accept(),说明事件已经处理完,不会在想父组件传播,如果返回FALSE或者调用ignore()表明这个事件没有被处理完,QT会传递给其父组件继续处理。

1.3.2            自定义事件处理函数

要实现自定义的事件处理函数,可以按照上图的流程,从流程中的某个点着手,将事件接收过来处理。

(1)   重写事件响应函数

例如widget类继承于QWidget,QWidget有keyPressEvent函数,但是widget类重写了keyPressEvent函数,会覆盖基类的函数。按钮按下时,widget的keyPressEvent函数先处理事件。这种方法的局限性是只能处理特定的事件。

void AlarmCenter::keyPressEvent(QKeyEvent *event)

{

if (event->key() == 0x01000000)

{

int i = 1;

}

else {

//将除了Esc的按键返回给父控件QWidget处理

QWidget::keyPressEvent(event);

}

}

(2)重写QObject类的event函数

bool QWidget::event(QEvent *event)

{

if (e->type() == QEvent::KeyPress)

{

QKeyPressEvent *keyEvent = (QKeyEvent *)event;

return false;

}

return true;

}


(3)安装过滤器Filter过滤消息,

可以在QObject或者QApplication上安装过滤器。AlarmCenter的构造函数中安装过滤器installEventFilter(this);然后在类中实现eventFilter函数即可。

bool AlarmCenter:: eventFilter (QObject *target, QEvent *event)

{

if (event->type() == QEvent::KeyPress)

{

int i = 1;

return true;

}

else {

//将除了Esc的按键返回给父控件QWidget处理

return QWidget::eventFilter(target, event);

}

}

(4)   重写QApplication的notify函数

先要自定义自己的MyApplication类,继承于QApplication,然后重写QApplication的notify函数,在notify函数内部建立过滤消息处理,如果要传递事件给其他部件,可以通过postEvent或sendEvent发送给其他部件。

自定义的Application类头文件如下:

#ifndef MYAPPLICATION_H

#define MYAPPLICATION_H

#include <QApplication>

#include <QEvent>

class MyApplication : public QApplication

{

public:

MyApplication(int & argc, char ** argv);

public:

bool notify(QObject *receiver, QEvent *e);//重写notify函数

};

#endif

自定义的Application类源文件如下:

#include "myapplication.h"

#include <QMouseEvent>

MyApplication::MyApplication(int & argc, char ** argv) : QApplication(argc, argv)

{

}

bool MyApplication::notify(QObject *receiver, QEvent *e)

{

//屏蔽MouseButtonPress、MouseButtonRelease和MouseMove事件

if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseMove)

{

//此处添加事件处理

return true;

}

return QApplication::notify(receiver, e);

}

1.4  定时器事件

1.4.1            QTimerEvent类实现定时器

(1)   用int id1 = startTimer(2000);函数启动定时器。

(2)   重写timerEvent函数,接收处理定时器事件

void  AlarmCenter::timerEvent(QTimerEvent *event)

{

if (event->timerId() == 1)

{

qDebug() << "1";

}

else

{

qDebug() << "not 1";

}

}

1.4.2            QTimer类实现定时器

(1)在源文件中添加头文件

#include<QTimer>

#include<QTime>

(2)在构造函数中添加代码新建QTimer对象,将QTimer::timeout信号关联到槽函数AlarmCenter::UpdateTimer,调用函数start启动定时器。

m_timer = NULL;

m_timer = new QTimer(this);

QObject::connect(m_timer, &QTimer::timeout, this, &AlarmCenter::UpdateTimer);

m_timer->start(1000);

(3)    实现定时器处理函数

void  AlarmCenter::UpdateTimer()

{

QTime time = QTime::currentTime();

QString str = time.toString("hh:mm");

}

1.4.3            只运行一次的定时器

采用QTimer::singleShot(10000,this,&AlarmCenter::UpdateTimer);10秒钟后会执行一次定时器。

1.5  事件过滤器

事件过滤器的作用是实现在一个部件中监控其他多个部件的事件,比如在一个QMainWindow中监控QMainWindow上面多个按钮、输入框、表格等多个部件的事件,进行逻辑分析处理。具体实现方式是通过Object的两个函数installEventFilter和重写函数eventFilter(QObject *target, QEvent *event)函数来接收事件,通过target参数来获取控件的对象,通过event参数来获取事件类型。这样在textEdit文本输入框中输入值的时候,只要键盘按钮按下,就会进入eventFilter中的keypress事件处理。

(1)  在构造函数中installEventFilter函数传入this指针,使得AlarmCenter作为textEdit的事件的接收者。

ui.textEdit->installEventFilter(this);

(2)  重写Qobject的eventFilter函数接收个控件的事件。

bool AlarmCenter::eventFilter(QObject *target, QEvent *event)

{

if (target==ui.textEdit)

{

if (event->type() == QEvent::KeyPress)

{

int i = 1;

return true;

}

else {

//将除了Esc的按键返回给父控件QWidget处理

return QMainWindow::eventFilter(target, event);

}

}

else

{

return QMainWindow::eventFilter(target, event);

}

}

1.6  SendEvent和postEvent的异同

1.6.1            函数的继承关系和属性

QApplication 继承于QGuiApplication,而QGuiApplication继承于 QCoreApplication,实际上这两个函数是QCoreApplication的静态函数。可以使用QApplication::sendEvent直接调用。

static bool sendEvent(QObject *receiver, QEvent *event);

static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority);

1.6.2            两个函数的异同

Sendevent会立即处理事件,在栈上创建临时事件变量,传入指针,调用结束后自动销毁。PostEvent函数则是先把事件放到事件队列中,需要在堆上创建,需要new。等到事件被处理完后,事件队列自动清除内存。例如我们创建一个spinBox,即带上下按钮的输入框。将QTdesigner中将取值范围设置为正负10000。然后通过自定义的按钮按下信号去控制spinBox的值发生变化。

控制spinbox向上按钮,使数字加1,如果放在定时器中,则会定时增加数值。

QKeyEvent myEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);

QApplication::sendEvent(ui.spinBox, &myEvent);

采用postEvent控制spinbox向下按钮,使数字减1,如果放在定时器中,则会定时减少数值。

QKeyEvent* myEventde=new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier);

QApplication::postEvent(ui.spinBox, myEventde);

QT---事件系统的更多相关文章

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

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

  2. Qt事件系统基本概念

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

  3. Qt事件系统之五:事件过滤器和事件的发送

    Qt提供了事件过滤器来实现在一个部件中监控其他多个部件的事件.事件过滤器与其他部件不同,它不是一个类,只是由两个函数组成的一种操作,用来完成一个部件对其他部件的事件的监视.这两个函数分别是 insta ...

  4. Qt事件系统之四:定时器事件与随机数

    一.定时器事件和随机数 QTimerEvent类用来描述一个定时器事件.对于一个QObject的子类,只需要使用int QObject::startTimer ( int interval)函数来开启 ...

  5. Qt事件系统之三:键盘事件

    QKeyEvent类用来描述一个键盘事件.当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件. QKeyEvent的key()函数可以获取具体的按键,对于Qt中给定的所有按键,可 ...

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

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

  7. Qt事件系统之一:Qt中的事件处理与传递

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

  8. Qt中的键盘事件,以及焦点的设置(比较详细)

    Qt键盘事件属于Qt事件系统,所以事件系统中所有规则对按键事件都有效.下面关注点在按键特有的部分: focus 一个拥有焦点(focus)的QWidget才可以接受键盘事件.有输入焦点的窗口是活动窗口 ...

  9. 用ISO C++实现自己的信号槽(Qt另类学习)

    qtc++objectsignalclassstring   目录(?)[-] Qt信号与槽 引入元对象系统 建立信号槽链接 信号的激活 槽的调用 全家福 零零散散写在后面 Q_OBJECT Conn ...

  10. Qt 学习之路 :Qt 绘制系统简介

    Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPainter用来执行绘制的 ...

随机推荐

  1. golang json用法讲解

    简介 json格式可以算我们日常最常用的序列化格式之一了,Go语言作为一个由Google开发,号称互联网的C语言的语言,自然也对JSON格式支持很好.但是Go语言是个强类型语言,对格式要求极其严格而J ...

  2. Html5之Web存储

    localStorage 方法存储的数据没有时间限制.第二天.第二周或下一年之后,数据依然可用. sessionStorage 方法针对一个session 进行数据存储.当用户关闭浏览器窗口后,数据会 ...

  3. update与select关联执行效率问题

    UPDATE fl_user_space u SET u.`course_count` = (SELECT COUNT(*) FROM fl_course c WHERE c.uid = u.uid) ...

  4. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem F (Codeforces 831F) - 数论 - 暴力

    题目传送门 传送门I 传送门II 传送门III 题目大意 求一个满足$d\sum_{i = 1}^{n} \left \lceil \frac{a_i}{d} \right \rceil - \sum ...

  5. VC++ 使用CreateProcess创建新进程

    https://www.cnblogs.com/fancing/p/6477918.html #include <windows.h> #include <tchar.h> # ...

  6. Base64编码为什么会使数据量变大?

    当把byte[]通过Convert.ToBase64String转换成Base64编码字符串时数据量明显变大,为何呢?这里就得先探究一下什么是Base64编码. Base64编码的思想是是采用64个基 ...

  7. centos7之安装wordpress

    wordpress安装教程如下: mysql安装可以参考我的博客园Centos构建Java环境:https://www.cnblogs.com/youcong/p/9118753.html 1.安装a ...

  8. Oracle SQL——inner jion;left join;right join的区别和使用场景

    背景 在一次面试的时候,面试官让我说一下这三者的使用场景和区别,当时瞬间懵逼,哈哈.回来赶快看一看,记下来. 详解 inner join 等值查询:返回两张表中,联结字段值相等的组合记录 举例:所有学 ...

  9. Python3基础 list in/not in 判断一个变量是否在列表中存在

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

  10. 《编写高质量代码:Web 前端开发修炼之道》 笔记与读后感

    编写高质量代码:Web 前端开发修炼之道/曹刘阳著. —北京:机械工业出版社,2010.5 第一版 涉及到的知识点: 1. CSS Sprites 在国内很多人叫css精灵,是一种网页图片应用处理方式 ...