1 Qt中的事件处理
1.1 Qt中的事件处理过程
GUI程序原理回顾,图形界面应用程序的消息处理模型如下:

思考:操作系统发送的消息如何转变成Qt信号?
Qt平台将系统产生的消息转换成Qt事件:
- Qt事件是一个QEvent的对象。
- Qt事件用于描述程序内部或外部发生的动作。
- 任意的QObject对象都具备事件处理的能力。

GUI应用程序的事件处理方式:
- Qt事件产生后立即被分发到QWidget对象。
- QWidget中的event(QEvent*)进行事件处理。
- event()根据事件类型调用不同的事件处理函数。
- 在事件处理函数中发送Qt中预定义的信号。
- 调用信号关联的槽函数。
场景分析:按钮点击

(图中的序号4应该在序号5之后。)
QPushButton事件处理分析:
- 接收到鼠标事件。
- 调用event(QEvent*)成员函数。
- 调用mouseReleaseEvent(QMouseEvent*)成员函数。
- 调用click()成员函数。
- 触发信号SIGNAL(clicked())。
事件(QEvent)和信号(SIGNAL)的不同:
- 事件由具体对象进行处理,而信号是由对象在进行事件处理的过程中主动产生的。
- 改写事件处理函数可能导致程序行为发生改变,但是信号是否存在对应的槽函数不会改变程序行为。
- 一般而言,信号在具体的事件处理函数中产生。
编程实验:自定义事件处理函数(改写按钮的点击事件)

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;
void mouseReleaseEvent(QMouseEvent *e);
public:
explicit QMyPushButton(QWidget* parent = 0, QButtonListener* listener = 0);
signals:
public slots:
};
#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 )
{
m_listener(this, e);
e->accept();
setDown(false);
}
else
{
QPushButton::mouseReleaseEvent(e);
}
}
Widget.h:
#ifndef _WIDGET_H_
#define _WIDGET_H_
#include <QtGui/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)
{
myButton.setText("QMyPushButton");
connect(&myButton, SIGNAL(clicked()), this, SLOT(onMyButtonClicked()));
}
void Widget::onMyButtonClicked()
{
qDebug() << "onMyButtonClicked()";
}
Widget::~Widget()
{
}
main.cpp:
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
1.2 Qt中事件的传递过程
首先我们需要了解一点:事件被组件对象处理后可能传递到其父组件对象,也可能不传递到父组件对象。
QEvent中的关键成员函数:
void ignore():接收者忽略当前事件,事件可能会传递给父组件。void accept():接收者期望处理当前事件。bool isAccepted():判断当前事件是否被处理。
编程实验:事件处理的顺序

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);
signals:
public slots:
};
#endif // MYLINEEDIT_H
MyLineEdit.cpp:
#include "MyLineEdit.h"
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>
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(); // 如果调用了ignore函数,事件则会被传递到其父组件
}
Widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include "MyLineEdit.h"
class Widget : public QWidget
{
Q_OBJECT
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 <QDebug>
#include <QEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent), myLineEdit(this)
{
}
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()
{
}
main.cpp:
#include <QtGui/QApplication>
#include "Widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
1.3 Qt中的事件过滤器
对于Qt中的事件过滤器:
- 事件过滤器可以对其他组件接收到的事件进行监控。
- 任意的QObject对象都可以作为事件过滤器使用。
- 事件过滤器对象需要重写eventFilter()函数。
组件通过installEventFilter()函数安装事件过滤器:
- 事件过滤器在组件之前接收到事件。
- 事件过滤器能够决定是否将事件转发到组件对象。

事件过滤器的典型实现:

编程实验:事件过滤器的使用
大部分代码和上面的代码都相同,这里只贴出安装事件过滤器、和事件过滤器的实现:
Widget::Widget(QWidget *parent)
: QWidget(parent), myLineEdit(this)
{
myLineEdit.installEventFilter(this);
}
bool Widget::eventFilter(QObject* obj, QEvent* e)
{
bool ret = true;
if( (obj == &myLineEdit) && (e->type() == QEvent::KeyPress) )
{
qDebug() << "Widget::eventFilter";
QKeyEvent* evt = dynamic_cast<QKeyEvent*>(e);
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;
}
参考资料:
1051

被折叠的 条评论
为什么被折叠?



