QT---事件系统
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---事件系统的更多相关文章
- Qt 事件系统浅析 (用 Windows API 描述,分析了QCoreApplication::exec()和QEventLoop::exec的源码)(比起新号槽,事件机制是更高级的抽象,拥有更多特性,比如 accept/ignore,filter,还是实现状态机等高级 API 的基础)
事件系统在 Qt 中扮演了十分重要的角色,不仅 GUI 的方方面面需要使用到事件系统,Signals/Slots 技术也离不开事件系统(多线程间).我们本文中暂且不描述 GUI 中的一些特殊情况,来说 ...
- Qt事件系统基本概念
(转自:http://www.cnblogs.com/andy1987/p/3322059.html) 1. QT事件系统 Qt应用程序的消息处理是基于事件驱动的,程序的每个动作都是由某个事件所触发的 ...
- Qt事件系统之五:事件过滤器和事件的发送
Qt提供了事件过滤器来实现在一个部件中监控其他多个部件的事件.事件过滤器与其他部件不同,它不是一个类,只是由两个函数组成的一种操作,用来完成一个部件对其他部件的事件的监视.这两个函数分别是 insta ...
- Qt事件系统之四:定时器事件与随机数
一.定时器事件和随机数 QTimerEvent类用来描述一个定时器事件.对于一个QObject的子类,只需要使用int QObject::startTimer ( int interval)函数来开启 ...
- Qt事件系统之三:键盘事件
QKeyEvent类用来描述一个键盘事件.当键盘按键被按下或者被释放时,键盘事件便会被发送给拥有键盘输人焦点的部件. QKeyEvent的key()函数可以获取具体的按键,对于Qt中给定的所有按键,可 ...
- Qt事件系统之二:鼠标事件和滚轮事件
在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图 ...
- Qt事件系统之一:Qt中的事件处理与传递
一.简介 在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的 ...
- Qt中的键盘事件,以及焦点的设置(比较详细)
Qt键盘事件属于Qt事件系统,所以事件系统中所有规则对按键事件都有效.下面关注点在按键特有的部分: focus 一个拥有焦点(focus)的QWidget才可以接受键盘事件.有输入焦点的窗口是活动窗口 ...
- 用ISO C++实现自己的信号槽(Qt另类学习)
qtc++objectsignalclassstring 目录(?)[-] Qt信号与槽 引入元对象系统 建立信号槽链接 信号的激活 槽的调用 全家福 零零散散写在后面 Q_OBJECT Conn ...
- Qt 学习之路 :Qt 绘制系统简介
Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPainter用来执行绘制的 ...
随机推荐
- python pip
如果pip的版本较低,可能导致pip时安装出错,所以我们要更新pip版本-- 查询pip版本 pip -V -- Linux and OS X 升级 pip install -U pip -- Win ...
- pagehelper调用mybatis报错java.lang.NoSuchMethodError:org.apache.ibatis.reflection.MetaObject.forObject
最近在升新的基础框架到spring cloud,启动时pagehelper报错,如下: java.lang.NoSuchMethodError:org.apache.ibatis.reflection ...
- 基于快速排序思想partition查找第K大的数或者第K小的数。
快速排序 下面是之前实现过的快速排序的代码. function quickSort(a,left,right){ if(left==right)return; let key=partition(a, ...
- webpack --watch和supervisor的不同
webpack --watch只是热打包,也就是前端代码的热加载,要实现后端代码的热加载,也就是热部署,需要使用supervisor 如何使用热部署可以参考这里:http://www.cnblogs ...
- 异步任务利器Celery(二)在django项目中使用Celery
Celery 4.0支持django1.8及以上的版本,低于1.8的项目使用Celery 3.1. 一个django项目的组织如下: - proj/ - manage.py - proj/ - __i ...
- django基础 -- 7.Ajax
一.ajax 的特点 1.异步交互:客户端发出一个请求后,需要等待服务器响应结束后, 才能发出第二个请求 2.局部刷新:给用户的感受是在不知不觉中完成请求和响应过程. 二.ajax 模板示例 ($.a ...
- Bootstrap3基础 img-rounded 图片的四个角改成圆角
内容 参数 OS Windows 10 x64 browser Firefox 65.0.2 framework Bootstrap 3.3.7 editor ...
- java 之 schema解析
一,schema约束 *dtd语法:<ELEMENT 元素名 约束> *schema符合xml的语法,xml语句 **一个xml中可以有多个schema,多个schema使用名称空间区分( ...
- WebLogic调用WebService提示Failed to localize、Failed to create WsdlDefinitionFeature
在本地Tomcat环境下调用WebService正常,但是部署到WebLogic环境中,则提示警告:[Failed to localize] MEX0008.PARSING_MDATA_FAILURE ...
- 题解——POJ 2234 Matches Game
这道题也是一个博弈论 根据一个性质 对于\( Nim \)游戏,即双方可以任取石子的游戏,\( SG(x) = x \) 所以直接读入后异或起来输出就好了 代码 #include <cstdio ...