如何在子窗口小部件下使用 eventfilter 来捕获自定义事件

Posted

技术标签:

【中文标题】如何在子窗口小部件下使用 eventfilter 来捕获自定义事件【英文标题】:how to use eventfilter under child widget to catch self define event 【发布时间】:2020-02-26 23:40:10 【问题描述】:

最近我需要将 Pong Gui 的按键事件类型替换为自定义事件类型 MyEvent(使用 UDP 信号代替 来控制游戏)。然而问题是,对于自定义事件,我似乎需要手动发送或发布它们,而事件过滤器无法接收自定义事件(内置的按键或鼠标点击似乎不需要手动发送)。事件过滤器安装在 mainwindow.cpp 中: ui->boardView->installEventFilter(gameloop iLoop); eventfilter在gameplay.cpp中实现: '''

bool Gameplay::eventFilter(QObject *target, QEvent *e)

    Q_UNUSED(target);

    bool handled = false;
    if(e->type() == MyEventType)
    
        MyEvent *myevent = (MyEvent *)e;
        if ( myevent->sg >0)
        
            //pong paddle move left
            iP1Direction = (iP1Direction == 0 ? -5 : 0);
            handled = true;
        
        else if ( myevent->sg <0 )
        
            //pong paddle move right
            iP1Direction  = (iP1Direction == 0 ? 5 : 0);
            handled = true;
        
    
    if(e->type() == MyEventType)
    
        qDebug()<<"abc";
        handled = true;
    
    return handled;

'''

main.cpp '''

#include <QtWidgets/QApplication>
#include "mainwindow.h"
#include "MyEvent.h"
#include <iostream>
#include <cmath>
int main(int argc, char *argv[])


    QApplication a(argc, argv);

    MainWindow w;
    w.show();



    for(int i=0;i<1000;i++)
    MyEvent myEvent1(MyEventType);
    myEvent1.set_ch(1);
    myEvent1.load_sg(1);
    QCoreApplication::postEvent(&w, &myEvent1);
    

    return a.exec();

'''

mainwindow.cpp 是

'''
//cited from https://github.com/ynonp/Pong
#include <QPen>
#include <QResizeEvent>
#include <QDebug>
#include <QtWidgets/QApplication>
#include "mainwindow.h"
#include "MyEvent.h"
#include <QCoreApplication>
#include <QEvent>
#include <QObject>
#include <QDebug>
#include <iostream>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    iScore ( 0 )

    ui->setupUi(this);

    QGraphicsScene *scene = new QGraphicsScene(this);

    QGraphicsRectItem *p1 = new QGraphicsRectItem(0, 0, 80, 20);
    p1->setBrush(QBrush(Qt::blue));
    QGraphicsRectItem *p2 = new QGraphicsRectItem(0, 0, 80, 20);
    p2->setBrush(QBrush(Qt::green));

    QGraphicsEllipseItem *ball = new QGraphicsEllipseItem(0, 0, 15, 15);
    ball->setBrush(QBrush(Qt::magenta));

    ui->boardView->setScene(scene);

    iLoop = new Gameplay(*scene, p1, p2, ball, this);
    QSize m(scene->sceneRect().size().width() + 10, scene->sceneRect().size().height() + 10);
    ui->boardView->setMinimumSize(m);

    resize(minimumSize());
    ui->boardView->installEventFilter(iLoop);


    QObject::connect(iLoop, SIGNAL(goal(int)),
                     this, SLOT(addScore(int)));



MainWindow::~MainWindow()

    delete ui;


void MainWindow::addScore(int count)

    iScore += count;
    ui->lcdNumber->display(iScore);

'''

那么如何将我的自定义事件输入 GUI 事件过滤器?

谢谢! ---------------------------------- 200227 谢谢总经理! 问题是当我们尝试发布到 ui->boardView 时,它会报告“未声明的标识符”,因为 ui->boardview 不是在 main.cpp 中定义的,而是在 mainwindow.cpp 中定义的

【问题讨论】:

【参考方案1】:

显示的代码存在一些基本问题。首先,如果您希望ui-&gt;boardView 接收事件,那么您应该将事件发送到ui-&gt;boardView:而不是像您在...中所做的那样发送到MainWindow 实例。

MainWindow w;
w.show();
for (int i = 0; i < 1000; i++) 
    MyEvent myEvent1(MyEventType);
    myEvent1.set_ch(1);
    myEvent1.load_sg(1);
    QCoreApplication::postEvent(&w, &myEvent1);

其次,一旦一个事件被处理,Qt 事件处理代码将是deleted,所以一般来说,您必须在堆上分配事件。所以上面的代码将导致delete 在无效的内存位置上被调用,从而导致未定义的行为。应该改成...

MainWindow w;
w.show();
for (int i = 0; i < 1000; i++) 
    auto *myEvent = new MyEvent1(MyEventType);
    myEvent1->set_ch(1);
    myEvent1->load_sg(1);
    QCoreApplication::postEvent(ui->boardView, myEvent1);

【讨论】:

谢谢,我们更进一步。但问题是它报告“未在此范围内声明 ui”。我们一直在努力解决这个问题,因为 ui 只在 mainwindow.cpp 中声明 尝试将显示的代码移动到 MainWindow 构造函数中。 emm...您的意思是将所有事件过滤器的内容移到主窗口中吗?还是主窗口(Qwidget *parent)还是~主窗口?切换出事件过滤器后仍然安装到 boardView 并且发送到主窗口的事件仍然没有触及 eventfilter/(ㄒoㄒ)/~~ 很抱歉一直打扰,并感谢您至少提供了解决问题的希望。整个代码可能有助于提供整个背景github.com/Zonghan-Barry-Gan/RTEP-EMG/tree/master/… 我们一直在努力解决它。我们该如何解决这个问题?

以上是关于如何在子窗口小部件下使用 eventfilter 来捕获自定义事件的主要内容,如果未能解决你的问题,请参考以下文章

在子创建后设置父时,子小部件对事件是透明的

在子小部件中,如何在 kivy 中获取父小部件的实例

QWidget如何在子小部件中接收keyPressEvent

QT在子窗口外单击关闭子窗口

如何使用 grid() 将小部件水平居中?

如何在不影响 Pyqt5 中的小部件的情况下将背景图像添加到主窗口