(二十八)Qt中的事件处理

Qt事件

1、  在Qt中,Qt是一个QEvent对象

2、  Qt事件用于描述程序内部或外部发生的动作

3、  任意的QObject对象都具备事件处理的能力(想要接受并处理事件的对象必须继承自QObject)

 

QEvent是所有事件对象的抽象基类

 

事件来源

1、Spontaneous events(自发事件)

由系统消息(鼠标按键、键盘按键灯)转化而来

2、Postedevents

由Qt或应用程序产生,会被放入事件队列

由QCoreApplication成员函数

void

postEvent ( QObject * receiver, QEvent * event )

void

postEvent ( QObject * receiver, QEvent * event, int priority )

发送

3、Sent events

由Qt或应用程序产生,不放入队列,直接被派发和处理

由QCoreApplication成员函数

bool

sendEvent ( QObject * receiver, QEvent * event )

发送

 

GUI应用程序的事件处理到槽

1、  Qt事件产生后被立即寄送到发生系统消息的QWidget对象

2、  QWidget中的event(QEvent *)按照Qt事件的类型分发给相应事件处理函数

3、  事件处理函数处理Qt事件

4、  事件处理函数中发送Qt中预定义的信号

5、  调用与信号关联的槽函数

 

//main.cpp

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

//QMyPushButton.h

#ifndef _QMYPUSHBUTTON_H_
#define _QMYPUSHBUTTON_H_
 
#include <QPushButton>
 
typedef void(QButtonListener)(QObject*,QMouseEvent*);
 
class QMyPushButton : public QPushButton
{
   Q_OBJECT
 
protected:
   QButtonListener* m_listener;
 
   //重写QPushButton的事件处理函数
   void mouseReleaseEvent(QMouseEvent *e);
public:
   explicit QMyPushButton(QWidget* parent = 0, QButtonListener* listener =0);
};
 
#endif // _QMYPUSHBUTTON_H_


//QMyPushButton.cpp

#include "QMyPushButton.h"
#include <QMouseEvent>
 
QMyPushButton::QMyPushButton(QWidget*parent, QButtonListener* listener):QPushButton(parent)
{
   m_listener = listener;
}
 
//重写改写事件处理函数,会改变程序的行为。
void QMyPushButton::mouseReleaseEvent(QMouseEvent*e)
{
   if(m_listener != NULL)
    {
       //调用自定义的事件处理函数,尽管按钮的clicked信号被连接到onMyButtonClicked槽函数,
       //但因自定义的m_listener函数里并不触发clicked信号,从而槽函数不会被调用。
       m_listener(this, e);
       e->accept();//事件被接收,就不再传递到父QWidget
 
       setDown(false); //按钮设置为“弹起”状态
    }
   else
    {
       //父类的mouseReleaseEvent会去调用clicked(),并触发SIGNAL(clicked())
       //从而调用到连接到该信号的槽函数
       QPushButton::mouseReleaseEvent(e); //调用父类
    }
}

//Widget.h

#ifndef _WIDGET_H_
#define _WIDGET_H_
 
#include <QWidget>
#include "QMyPushButton.h"
 
class Widget : public QWidget
{
   Q_OBJECT
   QMyPushButton myButton;
 
protected slots:
   void onMyButtonClicked();
 
public:
   Widget(QWidget *parent = 0);
   ~Widget();
};
 
#endif // _WIDGET_H_

//Widget.cpp

#include "Widget.h"
#include <qDebug>
 
//自定义事件处理函数
void onMyButtonMouseRelease(QObject*sender, QMouseEvent* e)
{
   qDebug() << "onMyButtonMouseRelease(QObject* sender,QMouseEvent* e)";
}
 
Widget::Widget(QWidget *parent)
    :QWidget(parent),myButton(this, onMyButtonMouseRelease) //实验2:myButton(this,0)
{
   myButton.setText("QMyPushButton");
 
   connect(&myButton, SIGNAL(clicked()), this,SLOT(onMyButtonClicked()));
}
 
//槽函数,用于接收按钮的clicked信号
void Widget::onMyButtonClicked()
{
   qDebug() << "onMyButtonClicked()" ;
}
 
Widget::~Widget()
{
}


区分事件(QEvent)与信号(SIGNAL):

事件由具体QObject对象进行处理

信号由具体QObject对象主动产生

改写事件处理函数可能导致程序行为发生变化

信号是否存在对应的槽函数不会改变程序行为

一般而言,信号在具体的事件处理函数中产生

 

一般情况下,使用Qt预定义的组件,使用信号,自定义组件,使用事件

 

event()函数

原型bool event( QEvent * event ) [virtualprotected]

 

1、  用于Qt事件的分发

2、  可以通过重写event()在分发事件之前做一些操作

3、  可以通过QEvent成员函数

Type

type () const

来判断将要被分发的Qt对象的类型,以便对特定类型的事件进行操作

4、如果当前事件使我们想要的并且已经被我们处理,return true告诉Qt当前事件处理完毕,可以去处理事件队列中的下一事件了,如果当前事件不是我们想要的return false或者return父类的event()函数,并以当前事件作为参数传递

 

 

Qt事件可能被传递给父组件

1、  Qt事件被组件对象处理后可能传递其父组件对象

2、  QEvent中关键成员函数(实际上只是在操作或判断一个标志位)

void

accept ()

void

ignore ()

bool

isAccepted () const

前两个成员函数分别告诉Qt

1)、接受者忽略了当前事件,这种情况下当前事件可能被传递给接受者的父组件

2)、接受者期望处理当前事件,这种情况下当前事件

后一个成员函数用来判断当前事件是否被处理

 

一般情况下不使用accept ()或ignore ()来指示当前事件是否被处理,而是如果期望忽略当前事件,调用父类的事件处理函数

 

//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:
   explicit MyLineEdit(QWidget* parent = 0);
   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 = 0);
 
   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()
{
 
}


 

事件过滤器:

1、事件过滤器可以对其他组件即将接收到的事件进行监控

2、任意的QObject对象都可以作为事件过滤器使用

3、事件过滤器对象需要重写

bool QObject::eventFilter ( QObject * watchedQEvent * event ) [virtual]

函数返回true表示事件已经处理,无需传递给watched,返回false则正常传递到watched

3、  事件过滤器在目标组件之前接收到事件

4、  事件过滤器能决定是否将事件转发到目标组件


注意事项:

1、如果一个组件安装了多个过滤器,则最后一个安装的会最先调用,类似于堆栈的行为。

2、事件过滤器和被安装的组件必须在同一线程,否则,过滤器不起作用

3、如果在install之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。

 

使用:

1、为事件过滤器对象重写eventFilter()函数

2、目标组件通过函数voidQObject::installEventFilter ( QObject * filterObj )安装事件过滤器

 

bool MainWindow::eventFilter(QObject *obj,QEvent *event)
 {
       if (obj == textEdit) //感兴趣对象
{
                if (event->type() ==QEvent::KeyPress) //感兴趣事件
{
                         QKeyEvent *keyEvent =static_cast<QKeyEvent*>(event);
                         if (keyEvent->key()== Qt::Key_Space)
                                                                 //…….
                         return true;
                }
       }
       // 不感兴趣的对象与事件调用父类同名函数执行默认处理
       return QMainWindow::eventFilter(obj, event);
}


 

 

//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:
   explicit MyLineEdit(QWidget* parent = 0);
   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 = 0);
 
   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()
{
}


Qt中五种事件处理方式,控制权由低到高分别为:

1、重写事件处理函数

2、重写event()函数

3、为单个组件安装事件过滤器

4、为QApplication安装事件过滤器

5、重写QCoreApplication的成员notify()函数

bool MyEvent::notify(QObject *target,QEvent *event) 
   { 
   if(event->type() == MyEventType) 
   { 
       //…… 
       return true; 
   } 
   return QCoreApplication::notify(target,event); 
   } 
 


 

 声明:
此文根据 狄泰学院唐老师的《QT实验分析教程》创作

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值