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中的事件处理(下)的更多相关文章

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

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

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

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

  3. 第30课 Qt中的文本编辑组件

    1. 3种常用的文本编辑组件的比较 单行文本支持 多行文本支持 自定义格式支持 富文本支持 QLineEdit (单行文本编辑组件) Yes No No No QPlainTextEdit (多行普通 ...

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

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

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

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

  6. 第47课 Qt中的调色板

    1. QPalette类 (1)QPalette类提供了绘制QWidget组件的不同状态所使用的颜色. (2)QPalette对象包含了3个状态的颜色描述 ①激活颜色组(Active):组件获得焦点使 ...

  7. 第32课 Qt中的文件操作

    1. Qt的中IO操作 (1)Qt中IO操作的处理方式 ①Qt通过统一的接口简化了文件和外部设备的操作方式 ②Qt中的文件被看作一种特殊的外部设备 ③Qt中的文件操作与外部设备的操作相同 (2)IO操 ...

  8. 第7课 Qt中的坐标系统

    1. 坐标系统 (1)GUI操作系统都有特定的坐标系统 (2)图形界面程序在坐标系统中进行窗口和部件的定位 (3)定位类型 ①顶级窗口部件的定位 ②窗口内部件的定位 ③窗口部件的大小设置 (4)QWi ...

  9. 第11课 Qt中的字符串类

    1. 历史遗留问题和解决方案 (1)历史遗留问题 ①C语言不支持真正意义上的字符串 ②C语言用字符数组和一组函数实现字符串操作 ③C语言不支持自定义类型,因此无法获得字符串类型 (2)解决方案 ①从C ...

随机推荐

  1. [调整] Firemonkey iOS 原生 Edit 透明框, 改变框色

    说明:iOS 原生 Edit 透明框 适用:Berlin Firemonkey 方法:在 StyleLookup 输入 transparentedit 效果: 如果有图片 Image 在这二个 Edi ...

  2. Linux-安装Oracle(CentOS-Oracle 12c)

    第一步:网络连接,在我的上一篇博客中有介绍,不再多说. 网络连接的目的:为了能使用yum命令,在网上直接下载文件. 第二步:前往oracle官网下载12c database服务器端的两个文件:(安装在 ...

  3. Verilog学习笔记简单功能实现(二)...............全加器

    先以一位全加器为例:Xi.Yi代表两个加数,Cin是地位进位信号,Cout是向高位的进位信号.列表有:   Xi     Yi    Cin Sum Cout 0 0 0 0 0 0 0 1 1 0 ...

  4. 【夯实PHP系列】PHP正则表达式

    一. 概述 1. 正则表达式的测试地址: http://tool.chinaz.com/regex/ 二.具体的常用正则表达式 1. 邮箱正则表达式: 1)\w[-\w.+]*@([A-Za-z0-9 ...

  5. .Net Core WebAPI 基于Task的同步&异步编程快速入门

    .Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...

  6. 【再探backbone04】单页应用的基石-路由处理

    前言 首先发一点牢骚,互联网公司变化就是快,我去一个团队往往就一年时间该团队就得解散,这不,公司居然把无线团队解散了,我只能说,我那个去!!! 我去年还到处让人来呢,一个兴兴向荣的团队说没就没了啊!我 ...

  7. sharepoint报HRESULT:0x80131904的错误的原因和解决方法

    在新建文件库的时候出现的.下上传文件和更改权限,都是在报这个HRESULT:0x80131904的错误,基本所有操作都报同一个错误,如下图: 错误原因 这个问题其实就是:sharepoint配置文件( ...

  8. 回收ImageView占用的图像内存

    使用方法: RecycleBitmap.recycleImageView(mSelectorView);   参数为imageview /** * 回收ImageView占用的图像内存; * 使用了本 ...

  9. 【ps】裁剪图片的某一块

    最近做我趣的专辑学了一点小技巧,我们切图的时候可能需要改变图片上的文字.需要图片某一部分的颜色块进行覆盖等.这时候就需要下面的技巧啦: 第一步:点v,变箭头选中图片 第二部:点M,变矩形框,划出需要裁 ...

  10. Linux 硬盘分区生效命令partprobe

    在Linux中使用fdisk命令进行分区时,有时会遇到"WARNING: Re-reading the partition table failed with error 16: Devic ...