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用来执行绘制的 ...
随机推荐
- c++ STL中的set和multiset
1.结构 set和multiset会根据特定的排序原则将元素排序.两者不同之处在于,multisets允许元素重复,而set不允许重复. set中的元素可以是任意类型的,但是由于需要排序,所以元素必须 ...
- 值得收藏的8个Web端组件库
值得收藏的8个Web端组件库 Ant Design 介绍:一个服务于企业级产品的设计体系,基于『确定』和『自然』的设计价值观和模块化的解决方案,让设计者专注于更好的用户体验. 组件库地址:https: ...
- TCP 的那些事儿(上)(转)
原文地址:http://kb.cnblogs.com/page/209100/ TCP是一个巨复杂的协议,因为他要解决很多问题,而这些问题又带出了很多子问题和阴暗面.所以学习TCP本身是个比较痛苦的过 ...
- UVa 12099 The Bookcase - 动态规划
题目大意 给定一些书,每个书有一个高度和宽度,然后将它们放到一个三层的书架里(要求每一层都不为空).定义书架的大小为每层最大的高度和 乘 每层宽度和的最大值.求最小的书架大小. 显然动态规划(直觉,没 ...
- c++中ifstream一次读取整个文件
转载:http://www.cnblogs.com/kex1n/p/4028428.html 第一种方法: 读取至std::string的情况: #include <string> #in ...
- python --- 07 补充( join 删除和添加 fromkeys ) 深浅拷贝
一.基本数据类型补充 1.join() "*".join("马虎疼") # 马*虎*疼 把传递进去的参数进行迭代. 获取到的每个元素和前面的*进行拼接. 得到 ...
- Restful framework【第十一篇】url路由控制
基本使用 -url控制 -传统的url配置 url(r'^books/$', views.BookView.as_view()), url(r'^books/(?P<pk>\d+)$', ...
- Kettle 连接 Oracle 问题总结
一. Driver class 'oracle.jdbc.driver.OracleDriver' could not be found, make sure the 'Oracle' driver ...
- Shiro源码分析
1.入口类:AbstractAuthenticator 用户输入的登录信息经过其authenticate方法: public final AuthenticationInfo authenticate ...
- OpenWRT路由器使用ipv6拨号上网教程
文章来源于群友,如有侵权,请联系我(aha971030@gmail.com)删除 原理介绍分析: 湖北E信地区可以使用ipv6拨号,好处是网络是上下对等不限速网络,也就是说,你的端口上限是多少,网上就 ...