zoukankan      html  css  js  c++  java
  • Qt 事件过滤器原理(installEventFilter函数)

    Qt事件过滤器原理(installEventFilter函数)

    事件过滤器用于拦截传递到目标对象的事件,这样可以实现监视目标对象事件的作用。
    1、Qt实现事件过滤器的步骤如下:
    ①、Qt调用
    void QObject::installEventFilter (QObject* filterObj)
    把filterObj对象安装(或注册)为事件过滤器,filterObj也称为过滤器对象。事件过滤器通常在构造函数中进行注册。
    ②、在上一步注册的filterObj对象,通过调用
    bool QObject::eventFilter(QObject* obj, QEvent* e);
    来接收拦截到的事件。也就是说拦截到的事件在filterObj对象中的eventFilter函数中处理。eventFilter的第一个参数obj指向的是事件本应传递到的目标对象。
    ③、使用QObject::removeEventFilter(QObject *obj)函数可以删除事件过滤器。
    2、事件过滤器处理事件的规则
    ①、过滤器对象的eventFilter()函数可以接受或拒绝拦截到的事件,若该函数返回false,则表示事件需要作进一步处理,此时事件会被发送到目标对象本身进行处理(注意:这里并未向父对象进行传递),若evetnFilter()返回true,则表示停止处理该事件,此时目标对象和后面安装的事件过滤器就无法获得该事件。
    ②、若同一对象安装了多个事件过滤器,则最后安装的过滤器首先被激活。
    3、为什么使用事件过滤器
    使用事件过滤器可以简化程序代码。比如按钮1和标签1,对按下A键的事件响应相同的操作,若不使用事件过滤器,则需要分别子类化按钮和标签部件,并重新实现各自的事件处理函数。再如使用同一个子类化按钮的类C创建的按钮1和按钮2,对按下键A,按钮1和按钮2需要作不同的响应,若不使用事件过滤器,则他们的响应是相同的,若使用事件过滤器,则可以拦截按钮1或按钮2的事件并作特殊处理。
    4、理解事件过滤器
    观察者模式:其原理为,设有一目标对象S,它有多个观察该对象的对象G1,G2,G3,当S发生变化时,S的观察者会依情形改变自身。应用于Qt事件过滤器,则是,首先使用S的成员函数installEventFilter函数把G1,G2,G3设置为S的观察者,所有本应传递给S的事件E,则先传递给观察者G1,G2,G3,然后观察者调用其成员函数eventFilter对传递进来的事件进行处理,若eventFilter返回true表示事件处理完毕,返回false则返回给被观察者S进行处理。见图2-13。
    在这里插入图片描述

    示例2.22:事件过滤器的使用

     1 #include <QApplication>
     2 #include<QWidget>
     3 #include<QMouseEvent>
     4 #include<QPushButton>
     5 #include<QObject>
     6 #include <iostream>
     7 using namespace std;
     8 class A:public QObject{public:  //该类的对象用作过滤器对象,使用事件过滤器需继承QObject
     9 bool eventFilter(QObject *w, QEvent *e){ 
    10 if(e->type()==QEvent::MouseButtonPress)
    11                 {cout<<w->objectName().toStdString(); //验证w为事件本应到达的目标对象
    12                 cout<<"=Ak"<<endl;
    13                     return 1;  //返回1表示该事件不再进一步处理
    14                 }
    15                 return 0;}  };  /*返回0表示其余事件交还给目标对象处理,本例应返回0,否则添加了该过滤器的安钮会无法显示。*/
    16 class B:public A{public:   //继承自类A
    17 bool eventFilter(QObject *w, QEvent *e){
    18 if(e->type()==QEvent::MouseButtonPress){
    19 cout<<w->objectName().toStdString()<<"=Bk"<<endl;
    20 return 0;}
    21 return 0;}    };
    22 class C:public QWidget{public: void mousePressEvent(QMouseEvent *e){cout<<"Ck"<<endl;}};
    23 class D:public QPushButton{public:void mousePressEvent(QMouseEvent *e){cout<<"DK"<<endl;}};
    24 
    25 int main(int argc, char *argv[]){
    26 QApplication a(argc,argv); 
    27 //创建对象,注意:本例父对象应先创建,以避免生命期过早结束
    28     A ma;       B mb;        C mc;        D *pd=new D;        D *pd1=new D;
    29     pd->setText("AAA");    pd->move(22,22);      pd1->setText("BBB");    pd1->move(99,22);
    30     //设置对象名
    31     ma.setObjectName("ma");       mb.setObjectName("mb");       mc.setObjectName("mc");
    32     pd->setObjectName("pd");       pd1->setObjectName("pd1");
    33     //设置父对象
    34     pd->setParent(&mc);    pd1->setParent(&mc);
    35     mb.setParent(&ma);    //36      //注册过滤器对象
    37     pd->installEventFilter(&mb);  //
    38     pd1->installEventFilter(&ma); //
    39 
    40 mc.resize(333,222);    mc.show();    a.exec();    
    41 return 0;     }

    程序运行结果及说明(见图2-14)
    在这里插入图片描述
    当用鼠标按下按钮AAA时,输出pd=Bk和Dk。因为按钮AAA安装的过滤器对象为mb,因此由mb的eventFilter函数处理该事件,输出pd=BK,此时mb::eventFilter()返回0,表示此事件需作进一步处理,于是把该事件传递给目标对象处理(即pd所指向的对象),注意:本例虽然为mb设置了父对象ma,但事件并不会传递给父对象处理,而是返回给目标对象。此时调用D::mousePressEvent函数,输出Dk,至此事件处理结束。用鼠标按下按钮BBB输出pd1=Ak的原理略(较简单)
    示例2.23:添加多个事件过滤器

     1 #include <QApplication>
     2 #include<QWidget>
     3 #include<QMouseEvent>
     4 #include<QPushButton>
     5 #include<QObject>
     6 #include <iostream>
     7 using namespace std;
     8 class A:public QObject{public:  //该类的对象用作过滤器对象,使用事件过滤器需继承QObject
     9 bool eventFilter(QObject *w, QEvent *e){ 
    10 if(e->type()==QEvent::MouseButtonPress)
    11                 {cout<<w->objectName().toStdString(); //验证w为事件本应到达的目标对象
    12                 cout<<"=Ak"<<endl;
    13                     return 1;  //返回1表示该事件不再进一步处理
    14                 }
    15                 return 0;}  };  /*返回0表示其余事件交还给目标对象处理,本例应返回0,否则添加了该过滤器的安钮会无法显示。*/
    16 class B:public A{public:   //继承自类A
    17 bool eventFilter(QObject *w, QEvent *e){
    18 if(e->type()==QEvent::MouseButtonPress){
    19 cout<<w->objectName().toStdString()<<"=Bk"<<endl;
    20 return 0;}
    21 return 0;}    };
    22 class C:public QWidget{public: void mousePressEvent(QMouseEvent *e){cout<<"Ck"<<endl;}};
    23 class D:public QPushButton{public:void mousePressEvent(QMouseEvent *e){cout<<"DK"<<endl;}};
    24 
    25 int main(int argc, char *argv[]){
    26 QApplication a(argc,argv); 
    27 //创建对象,注意:本例父对象应先创建,以避免生命期过早结束
    28     A ma;       B mb;        C mc;        D *pd=new D;        D *pd1=new D;
    29     pd->setText("AAA");    pd->move(22,22);      pd1->setText("BBB");    pd1->move(99,22);
    30     //设置对象名
    31     ma.setObjectName("ma");       mb.setObjectName("mb");       mc.setObjectName("mc");
    32     pd->setObjectName("pd");       pd1->setObjectName("pd1");
    33     //设置父对象
    34     pd->setParent(&mc);    pd1->setParent(&mc);
    35     mb.setParent(&ma);    //36      //注册过滤器对象
    37     pd->installEventFilter(&mb);  //
    38     pd1->installEventFilter(&ma); //
    39 
    40 mc.resize(333,222);    mc.show();    a.exec();    
    41 return 0;     }

    程序运行结果及说明(见图2-15)
    在这里插入图片描述
    按钮AAA安装的过滤器对象依次为ma,mb,mc,mc1,
    因此按下鼠标时,依次调用对象mc1,mc,mb,ma(即逆序)
    的eventFilter函数,需要注意的是:当安装了多个事件过滤
    器之后,eventFilter函数返回0并不会使事件返回给目标对
    象,而是传递给下一个过滤器对象,当所有过滤器对象都不处理该事件时才会传递给目标对象。

  • 相关阅读:
    对<Effective Python: 编写高质量Python代码的59个有效方法>中知识点的总结和扩展
    那些年在使用python过程中踩的一些坑。
    java学习心得——Hutool工具类ExcelUtil
    java学习心得——String对象Replace
    java学习心得——Quartz 自定义定时器的操作
    ThoughtWorks.QRCode 生成二维码名片(实现二维码内容换行)
    这么多年第一次自己去用游标和临时表
    BASE64码转图片
    Sql常用函数
    关于EF查询表里的部分字段
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/13780235.html
Copyright © 2011-2022 走看看