问题
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 QObject
s. 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