如何从 QML 检测 dataChanged() 和 resourcesChanged()
How to detect dataChanged() and resourcesChanged() from QML
以下代码:
Item{
onDataChanged: console.log("Data changed")
}
Item{
onResourcesChanged: console.log("Resources changed")
}
分别抛出Cannot assign to non-existent property "onDataChanged"
和Cannot assign to non-existent property "onResourcesChanged"
。
childrenChanged()
信号不是这种情况。这样做的原因是在 qtdeclarative/src/quick/items/qquickitem.h
中, children
属性 声明为:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
但 data
或 resources
并非如此。它们声明为:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false)
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> resources READ resources DESIGNABLE false)
没有 changed()
信号。为什么要选择这种设计来特别隐藏对不可见子项的更改?此外,如何从 QML 中检测到 data
上的变化?
为什么需要这个?
一种可能的解决方法是监听 child events。我写了一个快速附加类型的 PoC :
ChildListener.h :
#ifndef CHILDLISTENER_H
#define CHILDLISTENER_H
#include <QObject>
#include <QtQml>
class ChildListener : public QObject {
Q_OBJECT
public:
ChildListener(QObject *object) : QObject(object) {
if (object)
object->installEventFilter(this);
}
static ChildListener *qmlAttachedProperties(QObject *object) {
return new ChildListener(object);
}
signals:
void childAdded(QObject* child);
void childRemoved(QObject* child);
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
Q_UNUSED(obj)
if (QChildEvent *childEvent = dynamic_cast<QChildEvent*>(event)) {
if (childEvent->added())
emit childAdded(childEvent->child());
if (childEvent->removed())
emit childRemoved(childEvent->child());
}
return false;
}
};
QML_DECLARE_TYPEINFO(ChildListener, QML_HAS_ATTACHED_PROPERTIES)
#endif // CHILDLISTENER_H
用 qmlRegisterUncreatableType<ChildListener>("fr.grecko.ChildListener", 1, 0, "ChildListener", "ChildListener can only be accessed as an attached type.");
注册它,你现在可以像这样使用它了:
import fr.grecko.ChildListener 1.0
/* ... */
Timer {
id: foo
objectName: "My name is foo"
}
Item {
ChildListener.onChildAdded: print("child added : ", child)
data: [foo];
}
这在控制台中输出:qml: child added : QQmlTimer(0x7ffe22f538e0, "My name is foo")
以下代码:
Item{
onDataChanged: console.log("Data changed")
}
Item{
onResourcesChanged: console.log("Resources changed")
}
分别抛出Cannot assign to non-existent property "onDataChanged"
和Cannot assign to non-existent property "onResourcesChanged"
。
childrenChanged()
信号不是这种情况。这样做的原因是在 qtdeclarative/src/quick/items/qquickitem.h
中, children
属性 声明为:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QQuickItem> children READ children NOTIFY childrenChanged DESIGNABLE false)
但 data
或 resources
并非如此。它们声明为:
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> data READ data DESIGNABLE false)
Q_PRIVATE_PROPERTY(QQuickItem::d_func(), QQmlListProperty<QObject> resources READ resources DESIGNABLE false)
没有 changed()
信号。为什么要选择这种设计来特别隐藏对不可见子项的更改?此外,如何从 QML 中检测到 data
上的变化?
为什么需要这个?
一种可能的解决方法是监听 child events。我写了一个快速附加类型的 PoC :
ChildListener.h :
#ifndef CHILDLISTENER_H
#define CHILDLISTENER_H
#include <QObject>
#include <QtQml>
class ChildListener : public QObject {
Q_OBJECT
public:
ChildListener(QObject *object) : QObject(object) {
if (object)
object->installEventFilter(this);
}
static ChildListener *qmlAttachedProperties(QObject *object) {
return new ChildListener(object);
}
signals:
void childAdded(QObject* child);
void childRemoved(QObject* child);
protected:
bool eventFilter(QObject *obj, QEvent *event) override {
Q_UNUSED(obj)
if (QChildEvent *childEvent = dynamic_cast<QChildEvent*>(event)) {
if (childEvent->added())
emit childAdded(childEvent->child());
if (childEvent->removed())
emit childRemoved(childEvent->child());
}
return false;
}
};
QML_DECLARE_TYPEINFO(ChildListener, QML_HAS_ATTACHED_PROPERTIES)
#endif // CHILDLISTENER_H
用 qmlRegisterUncreatableType<ChildListener>("fr.grecko.ChildListener", 1, 0, "ChildListener", "ChildListener can only be accessed as an attached type.");
注册它,你现在可以像这样使用它了:
import fr.grecko.ChildListener 1.0
/* ... */
Timer {
id: foo
objectName: "My name is foo"
}
Item {
ChildListener.onChildAdded: print("child added : ", child)
data: [foo];
}
这在控制台中输出:qml: child added : QQmlTimer(0x7ffe22f538e0, "My name is foo")