QT事件过滤器
事件过滤器(Event Filter)是一种强大的机制,允许你在事件到达目标对象之前拦截和处理这些事件。事件过滤器可以用于全局事件处理、调试、性能优化等多种场景。
事件过滤器是一个实现了 QObject::eventFilter 虚函数的对象。通过调用 QObject::installEventFilter 方法,可以将事件过滤器安装到目标对象上。当目标对象接收到事件时,事件会首先传递给事件过滤器进行处理。
实现步骤:
1. 创建事件过滤器类: 创建一个继承自 QObject 的类,并重写 eventFilter 方法。
class MyEventFilter : public QObject {
Q_OBJECT
public:
MyEventFilter(QObject *parent = nullptr);
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
};
2. 实现 eventFilter 方法: 在 eventFilter 方法中处理你感兴趣的事件,并决定是否继续传递事件给目标对象。
bool MyEventFilter::eventFilter(QObject *watched, QEvent *event) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
// 处理 Tab 键事件
qDebug() << "Tab key pressed";
return true; // 阻止事件继续传递
}
}
return QObject::eventFilter(watched, event); // 继续传递事件
}
3. 安装事件过滤器: 使用 QObject::installEventFilter 方法将事件过滤器安装到目标对象上。
MyEventFilter *filter = new MyEventFilter(this);
QLineEdit *lineEdit = new QLineEdit(this);
lineEdit->installEventFilter(filter);
性能影响:事件过滤器可能会影响应用程序的性能,特别是在处理大量事件时。因此,应谨慎使用事件过滤器,并确保其逻辑尽可能高效。
事件传递顺序:事件过滤器在目标对象的 event 方法之前调用。如果事件过滤器返回 true,事件将不会传递给目标对象。
移除事件过滤器:可以使用 QObject::removeEventFilter 方法移除已安装的事件过滤器。
引例
#include <QApplication>
#include <QLineEdit>
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>
class MyEventFilter : public QObject {
Q_OBJECT
public:
MyEventFilter(QObject *parent = nullptr) : QObject(parent) {}
protected:
bool eventFilter(QObject *watched, QEvent *event) override {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if (keyEvent->key() == Qt::Key_Tab) {
qDebug() << "Tab key pressed";
return true; // 阻止事件继续传递
}
}
return QObject::eventFilter(watched, event); // 继续传递事件
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QLineEdit lineEdit;
MyEventFilter filter;
lineEdit.installEventFilter(&filter);
lineEdit.show();
return app.exec();
}
#include "main.moc"
示例
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLabel>
#include <QImage>//此类用于加载图片
#include <QMouseEvent>
#include <QEvent>
#include <QBoxLayout>
#include <QTransform>//二维变换矩阵
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
private:
QLabel *label1img;
QLabel *label2img;
QLabel *label3img;
QLabel *label;
QImage img1;
QImage img2;
QImage img3;
public:
//重写 eventFilter 方法
bool eventFilter(QObject *obj, QEvent *event) override;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//删除当前布局Layout
QLayout *layout = this->layout();
if (layout!= nullptr) {
delete layout;
}
setWindowTitle("事件过滤器");
label = new QLabel("状态提示");//状态提示
label->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);//设置图片居中
label1img = new QLabel();
label1img->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);//设置图片居中
label2img = new QLabel();
label2img->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);//设置图片居中
label3img = new QLabel();
label3img->setAlignment(Qt::AlignCenter|Qt::AlignVCenter);//设置图片居中
img1.load("D:/1.png");//图片1
img2.load("D:/1.png");//图片2
img3.load("D:/1.png");//图片3
label1img->setPixmap(QPixmap::fromImage(img1));//设置图片1
label2img->setPixmap(QPixmap::fromImage(img2));//设置图片2
label3img->setPixmap(QPixmap::fromImage(img3));//设置图片3
QHBoxLayout *la = new QHBoxLayout();
la->addWidget(label1img);
la->addWidget(label2img);
la->addWidget(label3img);
QVBoxLayout *layout1 = new QVBoxLayout(this);//设置布局
layout1->addWidget(label);
layout1->addLayout(la);
//安装事件过滤器
label1img->installEventFilter(this);
label2img->installEventFilter(this);
label3img->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
//事件过滤
//@param obj 接收事件的对象
//@param event 事件对象
//返回值:true表示事件被处理,false表示事件未被处理
bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
if (obj == label1img) {
if (event->type() == QEvent::MouseButtonPress) { //鼠标按下事件
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); //转换为鼠标事件
if (mouseEvent->button() == Qt::LeftButton) {
label->setText("鼠标左键点击图片1");
}else if (mouseEvent->button() == Qt::RightButton) {
label->setText("鼠标右键点击图片1");
}else if (mouseEvent->button() == Qt::MiddleButton) {
label->setText("鼠标中键点击图片1");
}
//放大图片
QTransform transform;//设置变换
transform.scale(1.5, 1.5);//放大倍数
label1img->setPixmap(label1img->pixmap().transformed(transform));//设置图片
}
else if (event->type() == QEvent::MouseButtonRelease) { //鼠标释放事件
label->setText("鼠标释放图片1");
//还原图片
label1img->setPixmap(QPixmap::fromImage(img1));//设置图片
}
}
if (obj == label2img) {
if (event->type() == QEvent::MouseButtonPress) { //鼠标按下事件
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); //转换为鼠标事件
if (mouseEvent->button() == Qt::LeftButton) {
label->setText("鼠标左键点击图片1");
}else if (mouseEvent->button() == Qt::RightButton) {
label->setText("鼠标右键点击图片1");
}else if (mouseEvent->button() == Qt::MiddleButton) {
label->setText("鼠标中键点击图片1");
}
//放大图片
QTransform transform;//设置变换
transform.scale(1.5, 1.5);//放大倍数
label2img->setPixmap(label2img->pixmap().transformed(transform));//设置图片
}
else if (event->type() == QEvent::MouseButtonRelease) { //鼠标释放事件
label->setText("鼠标释放图片2");
//还原图片
label2img->setPixmap(QPixmap::fromImage(img2));//设置图片
}
}
return QMainWindow::eventFilter(obj, event);//先交给父类处理
}