文章目录
- 1 事件机制
- 2 ignore 和 accept
- 3 bool event(QEvent *event);
- 4 bool eventFilter(QObject *watched, QEvent *event);
- 5 总结
1 事件机制
事件传递图:
记录一下事件的传递顺序,主要围绕 QEventFilter, QEvent, QKeyEvent等事件展开:
首先自定义一个继承于QLineEdit的类MyEdit
#include <QtWidgets/QWidget>
#include "ui_testwidgetradius.h"
#include "myedit.h"
#include <QKeyEvent>
class CTestWidgetRadius : public QWidget
{
Q_OBJECT
public:
CTestWidgetRadius(QWidget *parent = Q_NULLPTR);
protected:
void keyPressEvent(QKeyEvent *event);
private:
Ui::CTestWidgetRadiusClass ui;
MyEdit* myEdit = nullptr;
};
#include "testwidgetradius.h"
#include <QStyleOption>
#include <QPainter>
#include <QDebug>
#include <QBitmap>
#include <QTextCodec>
#include <iostream>
#include <QToolTip>
bool CTestWidgetRadius::m_isHover = false;
QPoint CTestWidgetRadius::m_lastPoint = QPoint();
CTestWidgetRadius::CTestWidgetRadius(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
}
void CTestWidgetRadius::keyPressEvent(QKeyEvent *event)
{
qDebug() << "parent keyPressEvent";
}
#include <QLineEdit>
#include <QKeyEvent>
#include <QEvent>
class MyEdit : public QLineEdit
{
Q_OBJECT
protected:
void keyPressEvent(QKeyEvent *);
public:
MyEdit(QWidget *parent);
~MyEdit();
};
#include <QDebug>
MyEdit::MyEdit(QWidget *parent)
: QLineEdit(parent)
{
}
MyEdit::~MyEdit()
{
}
void MyEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "myEdit keyPressEvent";
}
重写了keyPressEvent(QKeyEvent *event)这个函数之后,当我们在编辑框里面输入时,就会发现会触发这个键盘按下的事件,并且执行重写函数的代码,打印"myEdit keyPressEvent",但是此时并不能将你在键盘输入的字符显示在编辑框里面,这是因为你覆盖了QLineEdit的keyPressEvent(QKeyEvent *event)的内容,这个内容里面就包含了输入的一些处理,所以要想实现自己的代码,又想要实现父类的功能,就需要调用父类的函数,如下所示:
void MyEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "myEdit keyPressEvent";
QLineEdit::keyPressEvent(event);//调用父类的函数 以实现空间原本的功能
}
这个时候就发现,可以顺利的键入字符了。此时你会发现只打印了"myEdit keyPressEvent",并没有打印"parent keyPressEvent",那么如何将这个事件传递呢?
2 ignore 和 accept
修改代码如下:
void MyEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << "myEdit keyPressEvent";
QLineEdit::keyPressEvent(event);//调用父类的函数 以实现控制原本的功能
event->ignore();//相当于 返回一个setAccepted(false) 传递事件给父类
}
此时就会打印myEdit keyPressEvent" 和 “parent keyPressEvent"了。这是因为调用ignore()只会这个事件就会被忽略,那这个事件就会继续传递,传递到他的父类去,也就是这里的Widget,就会执行父类的keyPressEvent(QKeyEvent *event)从而打印出"parent keyPressEvent”。
这里的 event->ignore();和setAccepted(false);作用是一样的。同理如果调用setAccepted(true);表示控件接收了这个事件,那么这个事件就不会继续传递了,和接受事件相对应的函数是event->accept();。
3 bool event(QEvent *event);
这个函数的级别是很高的,所有的具体的事件例如 void mousePressEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *);等事件,都会先由bool event(QEvent *event);函数来处理。接下来在myEdit类里面实现这个函数:
bool MyEdit::event(QEvent *event)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "myEdit event";
return false;//返回true 就不会继续传递了,设置为false会传递给父类
}
};
这个时候会打印出"myEdit event" 和 “parent keyPressEvent”,这是因为在event(QEvent *event) 函数中返回了false,表示这个控件不接收这个事件,那么这个事件就会继续传递到父类去,如果这里接受了事件,那么事件就不会传到父类去了。
4 bool eventFilter(QObject *watched, QEvent *event);
在窗口里面实现eventFilter函数,并给控件安装过滤器
bool CTestWidgetRadius::eventFilter(QObject *watched, QEvent *event)
{
if (watched == myEdit)
{
if (event->type() == QEvent::KeyPress)
{
qDebug() << "widget EventFilter";
return false;
}
}
return QWidget::eventFilter(watched, event);
}
myEdit = new MyEdit(this);
myEdit->installEventFilter(this);
这个时候就会打印出
widget EventFilter
myEdit event
parent keyPressEvent
这是因为这里返回了false,表示没有myEdit不接收事件,那么这个事件就会传到event,因为event里面也返回了false,所以这个事件就会传到keyPressEvent(QKeyEvent *event),如果这个函数里面就收了事件,那么事件就停止传递,如果这个函数没有接收,那么这个事件会继续传递到父类。
5 总结
所以事件的传递顺序,是从eventFilter() ->event()-> MyEdit::keyPressEvent(QKeyEvent *event) ->QWidget::keyPressEvent(QKeyEvent *event).这个顺序传递的。当然如果其中一个环节返回了true,事件就终止了。