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 * watched, QEvent * 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实验分析教程》创作