描述
事件过滤器(Event Filter)是Qt中一个强大的事件处理机制,它可以在对象接收到事件之前截获事件,并进行自定义处理。事件过滤器可以在不修改对象自身代码的前提下,对其进行事件处理和拦截。
事件过滤器的使用过程如下:
-
创建一个
QObject
对象,为其安装事件过滤器。 -
重载事件过滤器的
eventFilte
r函数,实现自定义的事件拦截和处理。 -
在需要拦截和处理事件的对象上,调用
installEventFilter
函数,将事件过滤器安装到该对象上。 -
在事件过滤器中实现自定义事件处理逻辑。
-
在事件过滤器的eventFilter函数中,调用
QObject::eventFilter()
函数,将事件传递给下一个事件接收器,事件接收器可以是该对象本身或者其父对象。
使用事件过滤器可以对QWidget
、QApplication
、QCoreApplication
等对象进行事件处理,常用于实现自定义事件处理逻辑、事件日志等。
示例
以下是用于拦截并处理QLineEdit
对象的按键事件,实现只能输入数字:
#include <QDebug>
#include <QObject>
#include <QLineEdit>
#include <QKeyEvent>
#include <QRegExp>
class DigitFilter : public QObject
{
Q_OBJECT
public:
explicit DigitFilter(QObject *parent = nullptr) : QObject(parent){
m_regExp.setPattern("[a-zA-Z0-9]+$");
}
bool eventFilter(QObject *obj, QEvent *event) override
{
qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << event->type();
if(event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(isDigit(keyEvent->text().at(0)) && m_regExp.exactMatch(keyEvent->text()))
return false;
else
return true;
}else {
return QObject::eventFilter(obj, event);
}
}
private:
bool isDigit(const QChar &c)
{
return c >= QLatin1Char('0') && c <= QLatin1Char('9');
}
private:
QRegExp m_regExp;
};
// main.cpp
#include <QApplication>
#include <QLineEdit>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit lineEdit;
DigitFilter digitFilter;
lineEdit.installEventFilter(&digitFilter);
lineEdit.show();
return a.exec();
}
以上代码作用:
- 在上述代码中,新建了一个名为DigitFilter的QObject子类,该类继承QObject类并重载了eventFilter函数,该函数用于拦截QLineEdit对象的按键事件,并判断该事件传递的按键是否为数字,如果是则返回false,否则返回true。
- 使用installEventFilter函数将该事件过滤器安装到QLineEdit对象上,从而实现只能输入数字的功能。
sendEvent()
bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event);
使用notify()函数将事件事件直接发送给接收者。返回从事件处理程序返回的值。
事件发送后不会被删除。通常的方法是在堆栈上创建事件,例如:
QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);
postEvent()
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
将事件事件(以对象接收者作为事件接收者)添加到事件队列并立即返回。
事件必须在堆上分配,因为post事件队列将获得事件的所有权,并在事件被发布后将其删除。在事件发布之后再访问它是不安全的。
当控制返回到主事件循环时,存储在队列中的所有事件都将使用notify()函数发送。
事件按优先级降序排序,即高优先级事件排在低优先级事件之前。优先级可以是任何整数值,即在INT_MAX和INT_MIN之间,包括;更多细节可以参考Qt::EventPriority
。具有同等优先级的事件将按发布的顺序处理。
注意:这个函数是线程安全的。
示例
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//ui->lineEdit->installEventFilter(new DigitFilter);
ui->spinBox->installEventFilter(this);
ui->spinBox->setFocus();
QKeyEvent e(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier);
QApplication::sendEvent(ui->spinBox, &e);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched == ui->spinBox)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent* e = static_cast<QKeyEvent*>(event);
if(e->key() == Qt::Key_Space)
{
ui->spinBox->setValue(0);
return true;
}else {
return false;
}
}else {
return false;
}
}else {
return QMainWindow::eventFilter(watched, event);
}
}
运行后,spinBox
控件的值变为了1.
结论
万事开头难,然后中间难,最后结尾难
。