How to receive event whenever a QWidget is added to QApplication's widget tree?

[亡魂溺海] 提交于 2019-12-12 02:38:12

问题


I want to inspect something application wide. Specifically I'd like to inspect every widget that is added to the application.

Similar thing can be done in JavaScript/HTML, where you can add DOM mutation listener which fires on DOM changes.

Can I listen on added widgets upon QApplication? Specifically, capture widgets added to QApplication object as children OR widgets added to any of the top level widgets or their children, subchildren, etc...

If not possible, what is best workaround available?


回答1:


The most stable solution is likely to be to walk the object hierarchy every so often, starting with the QApplication as the root, and check each object with your predicate. This is going to be inefficient, which is why I asked for more information about what objects you actually want to query. On the other hand, for a test framework, you may not care so much about efficiency.

It might be possible to do something else, however. You can install event-filtering objects on any QObject, which define how they respond when they receive an event from Qt's event system. You could install an event filter on the root QApplication object (and recursively on any children created) that would check if the event is a QChildEvent and if added() returns true for it. If that's true, meaning a new child was added, you could then install this event filter onto that child as well. All other events would be passed on untouched. You can read more about installing event filters here. Essentially, a filter is a QObject subclass that defines the eventFilter() function, which returns true for events that should be filtered (stopped) and false otherwise. When this returns true, run your predicate on the newly-created object and install the same event filter on it.

One issue to be aware of with this is that the eventFilter() function only receives QObjects. You can learn if the object is a QWidget by calling isWidgetType(), but you don't know more than that. So as long as your predicate can make do with only methods and data defined for these general base classes, that should be OK.




回答2:


As per @bnaecker's answer, here is some code:

AddChildEventFilter.h

#include <QObject>
class QEvent;
class AddChildEventFilter: public QObject {
        Q_OBJECT
    public:
        AddChildEventFilter(QObject* parent=0);
    protected:
        bool eventFilter(QObject *obj, QEvent *event) override;
};

AddChildEventFilter.cpp

#include "AddChildEventFilter.h"
#include <QEvent>
#include <QDebug>
#include <QWidget>
#include <QChildEvent>
AddChildEventFilter::AddChildEventFilter(QObject* parent):QObject(parent) {}

bool AddChildEventFilter::eventFilter(QObject* obj, QEvent* event) {
    if(QWidget* widget = dynamic_cast<QWidget*>(obj)) {
        if(QChildEvent* chevent = dynamic_cast<QChildEvent*>(event)) {
            if(chevent->added()) {
                QObject* child = chevent->child();
                qDebug()<<"Child added: "<<child->metaObject()->className()<<"to"<<widget->metaObject()->className();
                child->installEventFilter(new AddChildEventFilter(child));
            }
        }
    }
    return false;
}

Usage:

#include "AddChildEventFilter.h"
#include <QWidget>
#include <QApplication>
void PrintAllEvents()
{
    for(QWidget* widget: QApplication::allWidgets()) {
        widget->installEventFilter(new AddChildEventFilter(widget));
    }
}


来源:https://stackoverflow.com/questions/39155748/how-to-receive-event-whenever-a-qwidget-is-added-to-qapplications-widget-tree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!