Qt中的事件处理
图形界面应用程序的消息处理模型
问题:操作系统发送的消息如何转变为Qt信号的?
Qt事件
Qt平台将系统产生的消息转换为Qt事件
-
Qt事件是一个QEvent的对象
-
Qt事件用于描述程序内部或外部发生的动作
-
任意的QObject对象都具备事件处理的能力
GUI应用程序的事件处理方式
- Qt事件产生后立即被分发到QWidget对象
- QWidget中的event(QEvent*) 进行事件处理
- event() 根据事件类型调用不同的事件处理函数
- 在事件处理函数中发送Qt中预定义的信号
- 调用信号关联的槽函数
情景分析:按钮点击
- OS接收到鼠标事件
- Qt接收到鼠标事件后调用event(QEvent*) 成员函数
- 调用mouseReleseEvent(QMouseEvent*) 成员函数
- 调用click() 成员函数
- 触发信号SIGNAL(clicked())
示例代码:自定义事件处理函数
//QMyPushButton.h
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:
};
//QMyPushButton.cpp
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);
}
}
//QWidget.h
class Widget : public QWidget
{
Q_OBJECT
QMyPushButton myButton;
protected slots:
void onMyButtonClicked();
public:
Widget(QWidget *parent = 0);
~Widget();
};
//QWidget.cpp
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()";
}
现象:当点击按钮时,有以下输出:
onMyButtonMouseRelease(QObject* sender, QMouseEvent* e)
问题:我们在自定义事件后,槽函数就不再被执行了,为什么呢?
事件(QEvent)和信号(SIGNAL)不同
- 事件由具体对象进行处理
- 信号由具体对象主动产生
- 改写事件处理函数可能导致程序行为发生改变
- 信号是否存在对应的槽函数不会改变程序行为
- 一般而言,信号在具体的事件处理函数中产生。
问题:自定义事件后还能继续父组件的事件吗?
QEvent中的关键成员函数
- void ignore()
- 接收者忽略当前事件,事件可能传递给父组件
- void accept()
- 接收者期望处理当前事件
- bool isAccepted()
- 判断当前事件是否被处理
示例代码:事件处理的顺序
//MyLineEdit.h
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = 0);
bool event(QEvent* e);
void keyPressEvent(QKeyEvent* e);
signals:
public slots:
};
//MyLineEdit.cpp
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.h
class Widget : public QWidget
{
Q_OBJECT
MyLineEdit myLineEdit;
public:
Widget(QWidget* parent = 0);
bool event(QEvent* e);
void keyPressEvent(QKeyEvent* e);
~Widget();
};
//Widget.cpp
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);
}
输出结果:
MyLineEdit::event
MyLineEdit::keyPressEvent
Widget::event
Widget::keyPressEvent