2016-03-23 4 views
0

Für ein Projekt muss ich QML-Komponenten zur Laufzeit aus C++ erstellen.Qt: onChildrenChanged nicht gestartet, wenn QML-Komponenten zur Laufzeit aus C++ - Code erstellt werden

Meine allgemeine Architektur ist die folgende:

Project1:

  • engine.h
  • Engine.cpp
  • CustObject.h
  • CustObject.cpp
  • plugin.h
  • Plugin.cpp
  • Dummy.qml

Projekt2:

  • main.cpp
  • main.qml

Was ich tun möchte, ist Engine.cpp als Objekt QML instanziiert (möglich seit ich es in der Plugin-Klasse registriert und für Project2) verfügbar gemacht habe und dann dynamisch CustObject-Instanzen (die ebenfalls von Project2 verwendet werden) von Engine erzeugt habe. Am Ende mag ich, wenn ich schreibe:

ApplicationWindow{ 
id: window 
visible: true 
    Engine{ 
     id: eng1 
     CustObject{ 
      id: custObj1 
     } 
    } 
} 

Das ist etwas wie das gleiche sein wird

ApplicationWindow { 
    id: window 
    visible: true 

    Button { 
     text: "add new child" 
     onClicked: { 
      console.log("QML: Number children before", eng1.children.length); 
      eng1.addNewChildren(); 
      console.log("QML: Number children after", eng1.children.length); 
     } 
    } 
    Engine{ 
     id: eng1 
     onChildrenChanged: console.log("Changed") 
    } 
} 

wie das Schreiben Und ich soll sehen, dass die Zahl der Kinder erhöht und onChildrenChanged von eng1 sein sollte gestartet.

Das Problem ist, dass weder die Anzahl der Kinder inkrementiert noch das Signal onChildrenChanged gestartet wird.

ich auch das andere Problem hatte, dass, um ein Kind den Elternteil, eng1 in meinem Fall an, ich die Funktion QQmlComponent verwendet (QQmlEngine * Motor, const QUrl & url, QObject * parent = 0) von QQMLComponent Klasse . Aber ich kann keinen Weg finden, meine CustObject-Klasse in eine QUrl umzuwandeln, da es keine .qml-Datei ist.

Daher habe ich zuerst versucht, ein Dummy-qml-Objekt namens: Dummy.qml anstelle von CustObject-Objekt hinzuzufügen. Dummy.qml sieht wie folgt aus:

engine.h:

#ifndef ENGINE_H 
#define ENGINE_H 

#include <QQuickItem> 
#include <QQmlComponent> 
#include <QQmlEngine> 
#include <QQmlContext> 


class Engine : public QQuickItem{ 
    Q_OBJECT 
public: 
    explicit Engine(QQuickItem* parent = 0); 

    virtual ~Engine(); 

    Q_INVOKABLE QObject* addNewChildren(); 

}; 

#endif // ENGINE_H 

Engine.cpp:

#include "Engine.h" 


Engine::Engine(QQuickItem* parent) : 
    QQuickItem(parent) 
{ 
} 

Engine::~Engine(){ } 


QObject* Engine::addNewChildren(){ 

    qDebug() << "CPP: Number children before " << this->children().size(); 

    QObject* parentEntity = this; 
    QQmlComponent* childrenEntity; 
    QQmlComponent component(qmlEngine(this), QUrl("qrc:///src/Dummy.qml")); 
    QQuickItem *childrenItem = qobject_cast<QQuickItem*>(component.create()); 
    QQmlEngine::setObjectOwnership(childrenItem, QQmlEngine::CppOwnership); 
    childrenItem->setParent(parentEntity); 
    childrenItem->setProperty("nb", 2); 

    qDebug() << "CPP: Number children after" << this->children().size(); 

    //qDebug() << "Property value:" << QQmlProperty::read(childrenItem, "nb").toInt(); 

    return childrenItem; 
} 

import QtQuick 2.0 

Item { 
    property int nb: 1 
} 

Der Code meiner Motor Klasse sieht wie folgt aus Aber meine Ausgabe wenn ich main führe.qml ist die folgende:

qml: QML: Number children before 0 
    CPP: Number children before 0 
    CPP: Number children after 1 
    qml: QML: Number children after 0 

Und ich kommentierte die Linie zu QQmlProperty entsprechenden :: lesen aufgrund der folgenden Fehler: „unvollständigen Typ‚QQmlProperty‘verwendet in verschachtelten name-Bezeichner qDebug() < <“ Wert der Immobilie: "< < QQmlProperty :: lesen (childrenItem," nb "). ToInt();" ^

Ich habe daher die folgenden Fragen:

  1. Warum ist die Zahl der Kinder Inkrementierung nicht von qml gesehen (aber sichtbar von CPP)?
  2. Warum wird onChildrenChanged nicht von qml gestartet?
  3. Wie kann ich dynamisch hinzufügen CustObject-Klasse (die als qml-Objekt aus Sicht von Project2 sichtbar ist, seit es registriert ist) anstelle von Dummy.qml?
  4. Wie liest man eine Eigenschaft eines dynamisch hinzugefügten Objekts in C++ direkt nach seiner Erstellung (d. H. Wie wird QQMlProperty :: read verwendet)?

Vielen Dank im Voraus für jede Hilfe, die Sie mir geben könnten!

+0

Dies ist ein privates Signal, das Sie nicht verwenden sollten. – dtech

+0

Vielen Dank für Ihre schnelle Antwort! Welches Signal sollte ich dann verwenden, wenn ein Kind zu meiner Engine hinzugefügt wird? Und haben Sie irgendwelche Ideen, warum meine Kinder Variable nicht von Qt Sichtpunkt aktualisiert wird, sondern von C++ ein Ja? – tearoomFlow

+0

Die Interna von Qt sind eher statisch und unflexibel, Sie haben nicht wirklich die Möglichkeit, sie zu ändern oder anzuzapfen. Du könntest es überschreiben, aber wer weiß, was du kaputt machen kannst, alles in allem ist es nicht schön. Eine bessere Strategie besteht darin, Ihr Design so zu ändern, dass es die Einschränkungen von Qt umgeht. Verfügen Sie über eine eigene benutzerdefinierte Funktion zum Erstellen von Objekten und zum Aussenden Ihres benutzerdefinierten Signals, um darüber zu informieren. – dtech

Antwort

6

Why is the number of children incrementation not seen from qml (but visible from cpp)?

QML nicht QObject::children() nicht verwendet, stattdessen verwendet es QQuickItem::childItems(). Ja, das stimmt, es gibt zwei verschiedene Kinderlisten, eine aus QObject und eine aus QQuickItem. Beide dienen verschiedenen Zwecken: Der eine von QObject dient hauptsächlich der Speicherverwaltung (Kinder werden gelöscht, wenn Eltern gelöscht werden), während der von QQuickItem für die "visuelle Hierarchie", z. Kinder werden auf ihre Eltern gezogen. Weitere Details finden Sie unter the docs.

Why is onChildrenChanged not launched from qml?

Da die onChildrenChanged wird nur dann, wenn QQuickItem::childItems() Änderungen emittiert, die es nicht tut. Rufen Sie setParentItem() zusätzlich zu setParent(), um das zu beheben.

How can I add dynamically CustObject class (which is visible as a qml object from Project2 point of view since it is registered) instead of Dummy.qml?

indem einfach das Objekt selbst zu schaffen und die parent und parentItem Einstellung. Sie brauchen QQmlComponent hier nicht zu verwenden.

QObject childrenItem = new CustObject(); 
childrenItem->setParent(parentEntity); 
childrenItem->setParentItem(parentEntity); 

How to read a property of a dynamically added object in C++ just after its creation (i.e. how to use QQMlProperty::read)?

QQuickItem::childItems() Aufruf den Trick tun soll, keine Notwendigkeit, eine Eigenschaft zu lesen. FWIW, da war wahrscheinlich ein #include <QQmlProperty> Code, der nicht funktionierte.

+0

Vielen Dank! Jetzt funktioniert es :) Ich habe jetzt ein anderes Problem: Ich möchte mein CustObject dynamisch erstellen, aber ich möchte das beginCreate (QQmlContext * publicContext) von QQmlComponent verwenden. Tatsächlich möchte ich, dass alle meine Eigenschaften gesetzt werden, bevor onChildrenChanged gestartet wird. Gibt es eine Möglichkeit, diese Funktion zu verwenden und gleichzeitig eine benutzerdefinierte Komponente zu verwenden? Weil ich jetzt nur die Verwendung dieser Funktion gesehen habe, indem ich loadUrl und qml object benutzt habe. – tearoomFlow

+0

Ich kann mir das im Moment nicht ansehen, ich schlage vor, Sie stellen eine neue Frage, damit andere es sehen können, Sie werden wahrscheinlich einige Antworten auf diese Weise bekommen. –

Verwandte Themen