第39课 Qt中的事件处理(下)
1. 事件的传递过程
(1)操作系统检测到用户动作时,会产生一条系统消息,该消息被发送到Qt应用程序
(2)Qt应用程序收到系统消息后,将其转化为一个对应的QEvent事件对象,并调用QObject::event()将其分发出去。
(3)事件对应被分发到当前正在操作的窗口部件上,该窗口部件会调用QWidget::event()函数来处理,然后,在这个函数内部又会调用其他的子函数(如KeyPressEvent或mouseReleaseEvent)来进行具体的处理。
(4)event函数处理完后,可能会将当前事件传递给父组件(parent)对象。但这个过程只是一种可能,也就是有一部分会被传递,有些并不需要被传递。
2. QEvent中的关键成员函数:实际上只是在操作或判断一个标志位
(1)void ignore():事件的接收者忽略当前事件,事件可能传递给父组件
(2)void accept();事件的接收者期望处理当前事件,表明我们自己写了事件处理函数,一般不需要被父组件再处理了。
(3)bool isAccepted();判断当前事件是否被处理
【编程实验】事件处理的顺序
//main.cpp
#include "Widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); } /*当在编辑框中按下按键时输出结果:(注意MyLineEdit的父组件,即w中的 的event事件并未被触发 MyLineEdit::event MyLineEdit::keyPressEvent */
//MyLineEdit.h
#ifndef MYLINEEDIT_H #define MYLINEEDIT_H #include <QLineEdit> class MyLineEdit : public QLineEdit { Q_OBJECT public: ); bool event(QEvent* e); void keyPressEvent(QKeyEvent* e); }; #endif // MYLINEEDIT_H
//MyLineEdit.cpp
#include "MyLineEdit.h" #include <QKeyEvent> #include <QDebug> MyLineEdit::MyLineEdit(QWidget* parent):QLineEdit(parent) { } bool MyLineEdit::event(QEvent* e) { if( e->type() == QEvent::KeyPress) { qDebug() << "MyLineEdit::event"; } return QLineEdit::event(e); } void MyLineEdit::keyPressEvent(QKeyEvent* e) { qDebug() << "MyLineEdit::keyPressEvent"; QLineEdit::keyPressEvent(e); // e->ignore(); //表示事件会继续传递给父组件,本例中为Widget对象 //如果注释或e-accept()表示不再传递,则父组件的 //event函数不会被触发 }
//Widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "MyLineEdit.h" class Widget : public QWidget { Q_OBJECT private: MyLineEdit myLineEdit; public: Widget(QWidget *parent = ); bool event(QEvent* e); void keyPressEvent(QKeyEvent* e); ~Widget(); }; #endif // WIDGET_H
//Widget.cpp
#include "Widget.h" #include <QEvent> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent),myLineEdit(this) { } //操作系统将消息转化为事件,并分发到了这个Widget,会首先调用 //这个Wiget的event函数,该函数可以收到多种的系统事件,同时其内部会根据event //事件的类型调用相应的事件处理函数,如keyPressEvent()。比如,当发生按键事件时 //会先调用event(),再调用后面的keyPressEvent() bool Widget::event(QEvent* e) { if(e->type() == QEvent::KeyPress) { qDebug() << "Widget::event"; } return QWidget::event(e); } void Widget::keyPressEvent(QKeyEvent *e) { qDebug() << "Widget::keyPressEvent"; QWidget::keyPressEvent(e); } Widget::~Widget() { }
3. Qt中的事件过滤器
(1)事件过滤器
①事件过滤器可以对其他组件接收到的事件进行监控
②任意的QObject对象都可以作为事件过滤器使用。
③事件过滤器对象需要重写eventFilter()函数。
(2)安装事件过滤器:installEventFilter()函数
①事件过滤器在组件之前接收到事件
②事件过滤器能够决定是否将事件转到到组件对象
(3)Qt中的事件过滤器与dll中的勾子的不同
①Qt中事件的过滤,是由事件的目标对象自己,发起过滤请求的。即委托过滤器,在自己接收事件前,先叫过滤器过滤一下。这意味着目标对象是知道这个过滤器的存在的。如下面例子中的myLineEdit.installEventFilter(this),就是myLineEdit委托Widget对事件进行过滤。
②而dll中的勾子不管目标对象愿不愿意,消息都会被拦下,而且目标对象本身也并不知道勾子的存在。
(4)事件过滤器的典型实现
//场景:将所有发往obj的事件先经过指定的过滤函数处理一下,然后再发往obj //返回true表示事件己经处理,无需再传递给obj对象了 //返回false则正常传递到obj对象 bool Widget::eventFilter(QObject* obj, QEvent* e) { if(/*根据obj判断是否是所需的目标对象*/) { if(/*根据e->type()判断是否是感兴趣的事件*/) { /*事件处理逻辑*/ } } /*调用父类中的同名函数*/ return QWidget::eventFilter(obj, e); }
【编程实验】事件过滤器的使用
//main.cpp
#include "Widget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
//MyLineEdit.h
#ifndef MYLINEEDIT_H #define MYLINEEDIT_H #include <QLineEdit> class MyLineEdit : public QLineEdit { Q_OBJECT public: ); bool event(QEvent* e); void keyPressEvent(QKeyEvent* e); }; #endif // MYLINEEDIT_H
//MyLineEdit.cpp
#include "MyLineEdit.h" #include <QKeyEvent> #include <QDebug> MyLineEdit::MyLineEdit(QWidget* parent):QLineEdit(parent) { } bool MyLineEdit::event(QEvent* e) { if( e->type() == QEvent::KeyPress) { qDebug() << "MyLineEdit::event"; } return QLineEdit::event(e); } void MyLineEdit::keyPressEvent(QKeyEvent* e) { qDebug() << "MyLineEdit::keyPressEvent"; QLineEdit::keyPressEvent(e); // e->ignore(); //表示事件会继续传递给父组件,本例中为Widget对象 //如果注释或e-accept()表示不再传递,则父组件的 //event函数不会被触发 }
//Widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "MyLineEdit.h" class Widget : public QWidget { Q_OBJECT private: MyLineEdit myLineEdit; public: Widget(QWidget *parent = ); bool event(QEvent* e); void keyPressEvent(QKeyEvent* e); bool eventFilter(QObject* obj, QEvent* e); ~Widget(); }; #endif // WIDGET_H
//Widget.cpp
#include "Widget.h" #include <QEvent> #include <QKeyEvent> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent),myLineEdit(this) { myLineEdit.installEventFilter(this);//安装事件过滤器,即让所有发往myLineEdit的事件 //先由经由eventFilter过滤,这里委派Widget的 //EventFilter来过滤 } //操作系统将消息转化为事件,并分发到了这个Widget,会首先调用 //这个Wiget的event函数,该函数可以收到多种的系统事件,同时其内部会根据event //事件的类型调用相应的事件处理函数,如keyPressEvent()。比如,当发生按键事件时 //会先调用event(),再调用后面的keyPressEvent() bool Widget::event(QEvent* e) { if(e->type() == QEvent::KeyPress) { qDebug() << "Widget::event"; } return QWidget::event(e); } void Widget::keyPressEvent(QKeyEvent *e) { qDebug() << "Widget::keyPressEvent"; QWidget::keyPressEvent(e); } //每个过滤器可以过滤多个对事的事件 bool Widget::eventFilter(QObject* obj, QEvent* e) { bool ret = true;//默认事件己经处理,不再传递到obj对象 //该过滤器只过滤发往myLineEdit对象的KeyPress事件 if ((obj == &myLineEdit) && (e->type() == QEvent::KeyPress)) { qDebug() << "Widget::eventFilter"; QKeyEvent* evt = dynamic_cast<QKeyEvent*>(e); //当按下数字键时返回false即让事件继续发生myLineEdit switch(evt->key()) { case Qt::Key_0: case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: case Qt::Key_8: case Qt::Key_9: ret = false; break; default: break; } } else { ret = QWidget::eventFilter(obj, e); } return ret; } Widget::~Widget() { }
4. 小结
(1)Qt应用程序有严格的事件处理顺序
(2)Qt事件在处理后可能传递给父组件对象
(3)可以通过installEventFilter()函数安装事件过滤器
(4)事件过滤器可以对其他组件接收到的事件进行监控
(5)事件过滤器能够决定是否将事件转发到组件对象
第39课 Qt中的事件处理(下)的更多相关文章
- 第38课 Qt中的事件处理(上)
1. GUI程序原理回顾 (1)图形界面应用程序的消息处理模型 (2)思考:操作系统发送的消息如何转变为Qt信号 2. Qt中的事件处理 (1)Qt平台将系统产生的消息转换为Qt事件 ①Qt事件是一个 ...
- Qt 中的事件处理(一)
1.图形界面应用程序的消息处理模型 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的 系统内核的消息通过事件处理转变成QT的信号 2. Qt中 ...
- 第30课 Qt中的文本编辑组件
1. 3种常用的文本编辑组件的比较 单行文本支持 多行文本支持 自定义格式支持 富文本支持 QLineEdit (单行文本编辑组件) Yes No No No QPlainTextEdit (多行普通 ...
- Qt 中的事件处理(二)
1. 回顾事件传递的过程 ①源头:操作系统 操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中, ②应用程序收到系统消息后, 他会将系统消息翻译成对应的 ...
- Qt事件系统之一:Qt中的事件处理与传递
一.简介 在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的 ...
- 第47课 Qt中的调色板
1. QPalette类 (1)QPalette类提供了绘制QWidget组件的不同状态所使用的颜色. (2)QPalette对象包含了3个状态的颜色描述 ①激活颜色组(Active):组件获得焦点使 ...
- 第32课 Qt中的文件操作
1. Qt的中IO操作 (1)Qt中IO操作的处理方式 ①Qt通过统一的接口简化了文件和外部设备的操作方式 ②Qt中的文件被看作一种特殊的外部设备 ③Qt中的文件操作与外部设备的操作相同 (2)IO操 ...
- 第7课 Qt中的坐标系统
1. 坐标系统 (1)GUI操作系统都有特定的坐标系统 (2)图形界面程序在坐标系统中进行窗口和部件的定位 (3)定位类型 ①顶级窗口部件的定位 ②窗口内部件的定位 ③窗口部件的大小设置 (4)QWi ...
- 第11课 Qt中的字符串类
1. 历史遗留问题和解决方案 (1)历史遗留问题 ①C语言不支持真正意义上的字符串 ②C语言用字符数组和一组函数实现字符串操作 ③C语言不支持自定义类型,因此无法获得字符串类型 (2)解决方案 ①从C ...
随机推荐
- 如何给Ubuntu12.10 安装Vmware Tools
众所周知在VMware虚拟机中安装好了VMware Tools,才能实现主机与虚拟机之间的文件共享,同时可支持自由拖拽的功能,鼠标也可在虚拟机与主机之前自由移动(而不再用按ctrl+alT释放),而且 ...
- Java中, for循环经典例子
循环的两种应用:穷举和迭代. break跳出整个循环 一.穷举:将所有可能的情况都走一遍,用if筛选出符合条件. 百鸡百钱: 一只公鸡1文钱,一只母鸡2文钱,一只小鸡半文钱,需要买100只鸡, 正好花 ...
- php实现设计模式之 桥接模式
<?php /** 桥接模式:将抽象部分与实现部分分离,使它们都可以独立的变化. * * 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,桥接模式就是应对这种多维度的变化 */ ...
- 从零开始学 Java - Spring AOP 实现用户权限验证
每个项目都会有权限管理系统 无论你是一个简单的企业站,还是一个复杂到爆的平台级项目,都会涉及到用户登录.权限管理这些必不可少的业务逻辑.有人说,企业站需要什么权限管理阿?那行吧,你那可能叫静态页面,就 ...
- 关系型数据库与NOSQL
本文转载自: http://www.cnblogs.com/chay1227/archive/2013/03/17/2964020.html(只作转载, 不代表本站和博主同意文中观点或证实文中信息) ...
- linux 文件系统简介
linux文件系统简介 文件系统是linux的一个十分基础的知识,同时也是学习linux的必备知识. 本文将站在一个较高的视图来了解linux的文件系统,主要包括了linux磁盘分区和目录.挂载基 ...
- .NET项目集成VS混淆加密
在微软.NET体系下开发软件难免遇到加密类库的需要,从商业的角度出发,使用像Xenocode .NET.Dotfuscator专业版等混淆器肯定是最好的选择, 作为一般小项目,我倒是觉得简单.易用达到 ...
- iOS之百度导航SDK的坐标转换
百度导航 iOS SDK的坐标转换代码示例,有需要的朋友可以参考下. //导航坐标--------------> 地图坐标 //假设从导航sdk取到了一个点坐标是(116.304847, 40. ...
- JavaScript单元测试框架JsUnit基本介绍和使用
JavaScript单元测试框架JsUnit基本介绍和使用 XUnit framework XUnit是一套标准化的独立于语言的概念和结构集合,用于编写和运行单元测试(Unit tests). 每一个 ...
- Golang(笔记) 顺序编程
package main import ( "fmt" "bufio" "io" "os" "strconv& ...