zoukankan      html  css  js  c++  java
  • Qt 中的事件处理(二)

    1. 回顾事件传递的过程
    ①源头:操作系统   操作系统检测到用户的动作时,就会产生一个系统消息,系统消息就会被发送到正在运行的Qt应用程序中,
    应用程序收到系统消息后, 他会将系统消息翻译成对应的QEvent事件对象,并调用QObject::event()将该对象分发下去,
    ③事件对象被分发到当前用户正在操作的窗口部件上去 ,该窗口部件是一个Qwidget的子类对象,该对象收到这个事件之后, 就会调用QWidget::event()函数来处理 ,该函数内部再调用其他的子函数(如KeyPressEvent或mouseReleaseEvent)进行具体的事件处理。
    ④可能会再被出传递到其父组件对象
     

    (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();判断当前事件是否被处理

    事件传递流程①事件先传递给指定窗口部件,确切的说传递给获得焦点窗口的部件,②如果该部件忽略该事件,那么这个事件就会传递给其父组件
    还需要注意当重新实现事件处理函数时,一般需要调用父组件的相应事件处理函数来实现其默认的行为
    如:
    void MyLineEdit::keyPressEvent(QKeyEvent *e)
    {
    qDebug()<<"MyLineEdit::keyPressEvent";
        QLineEdit::keyPressEvent(e);// 执行QLineEdit类的默认事件处理
     }

     实例事件处理的顺序

    //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
    */
    View Code

    //MyLineEdit.h

    #ifndef MYLINEEDIT_H
    #define MYLINEEDIT_H
    
    #include <QLineEdit>
    
    class MyLineEdit : public QLineEdit
    {
        Q_OBJECT
    public:
        explicit MyLineEdit(QWidget* parent = 0);
        bool event(QEvent* e);
        void keyPressEvent(QKeyEvent* e);
    };
    
    #endif // MYLINEEDIT_H
    View Code

    //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函数不会被触发
    }
    View Code

    //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 = 0);
    
        bool event(QEvent* e);
        void keyPressEvent(QKeyEvent* e);
    
        ~Widget();
    };
    
    #endif // WIDGET_H
    View Code

    //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()
    {
    
    }
    View Code

    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 <QApplication>
    #include "widget.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        Widget w;
        w.show();
        
        return a.exec();
    }
    

      widget.h

    #ifndef WIDGET_H
    #define WIDGET_H
    
    #include <QWidget>
    #include "mylineedit.h"
    
    class Widget : public QWidget
    {
        Q_OBJECT
        MyLineEdit* lineEdit;
    protected:
    void keyPressEvent(QKeyEvent *);
    public:
        Widget(QWidget *parent = 0);
        ~Widget();
        bool eventFilter(QObject* obj, QEvent *event);
    };
    
    #endif // WIDGET_H
    

      widget.cpp

    #include "widget.h"
    #include <QDebug>
    Widget::Widget(QWidget *parent)
        : QWidget(parent)
    {
        lineEdit=new  MyLineEdit(this);
    //安装事件过滤器,即让所有发往myLineEdit的事件先由经由eventFilter过滤,这里委派Widget的EventFilter来过滤
        lineEdit->installEventFilter(this);//在Widget上为lineedit安装事件过滤器了
    }
    
    Widget::~Widget()
    {
        
    }
    
    bool Widget::eventFilter(QObject *obj, QEvent *event)//事件过滤器
    {
    //该过滤器只过滤发往myLineEdit对象的KeyPress事件
        if(obj==lineEdit)//判断事件的对象是不是linEdit
        {
            if(event->type()==QEvent::KeyPress)//判断事件类型 
            {
                qDebug()<<"Widget::eventFilter";
            }
        }
        return QWidget::eventFilter(obj,  event);//最后返回QWidget类默认的事件过滤器的执行结果
    }
    
    void Widget::keyPressEvent(QKeyEvent *)
    { 
      qDebug()<<"Widget::keyPressEvent"; 
    }

    mylinedit.h

    #ifndef MYLINEEDIT_H
    #define MYLINEEDIT_H
    
    #include <QLineEdit>
    #include <QEvent>
    class MyLineEdit : public QLineEdit
    {
        Q_OBJECT
    protected:
        void keyPressEvent(QKeyEvent *e);
    
    public:
        explicit MyLineEdit(QWidget *parent = 0);
        
        bool event(QEvent* event);
    signals:
        
    public slots:
        
    };
    
    #endif // MYLINEEDIT_H
    

      

    mylineedit.cpp

    #include "mylineedit.h"
    #include <QDebug>
    #include <QkeyEvent>
    #include <QLineEdit>
    MyLineEdit::MyLineEdit(QWidget *parent) :
        QLineEdit(parent)
    {
    
    }
    
    bool MyLineEdit::event(QEvent *event)
    {
        if(event->type()==QEvent::KeyPress)
        qDebug()<<"MyLineEdit::event";
    
        return QLineEdit::event(event);//执行QLineEdit类的event()函数的默认操作   因为event()函数是有一个bool型返回值所以在函数的最后要使用return语句,这里一般是返回父类的event()函数的操作结果
    }
    
    
    void MyLineEdit::keyPressEvent(QKeyEvent *e)
    {
         qDebug()<<"MyLineEdit::keyPressEvent";
    
        // QLineEdit::keyPressEvent(e);
         e->ignore();
     }
    

      当点击键盘按键时,执行结果为:

    Widget::eventFilter 
    MyLineEdit::event 
    MyLineEdit::keyPressEvent 
    Widget::keyPressEvent 
    

    可以看到事件的传递顺序是:事件过滤器----->该部件的event()函数------>该部件的事件处理函数------>有可能是父组件的event函数(如果子部件ignore())

    3. 小结

    (1)Qt应用程序有严格的事件处理顺序

    (2)Qt事件在处理后可能传递给父组件对象

    (3)可以通过installEventFilter()函数安装事件过滤器

    (4)事件过滤器可以对其他组件接收到的事件进行监控

    (5)事件过滤器能够决定是否将事件转发到组件对象

  • 相关阅读:
    C++学习基础十一——子类对象向父类对象的转化
    C++学习基础十——子类构造函数与析构函数的执行
    C++学习基础九——继承
    浅谈OpenGL变换矩阵
    笔记-Ajax[3]-ajax类终极版;
    笔记-Ajax[1]-的整体流程。
    笔记-[js兼容]-滚动条的滚动距离的兼容性问题解决方法。
    JS中的一些不常用的知识点。
    笔记-[面向对象]-JS基于面向对象编程-[2]
    笔记-[面向对象]-JS基于面向对象编程-[1]
  • 原文地址:https://www.cnblogs.com/zhaobinyouth/p/7725465.html
Copyright © 2011-2022 走看看