2013-10-30 21 views
5

Dynamisch instanziieren ein QML-Objekt aus C++ ist well documented, aber was ich nicht finden kann ist, wie es mit vordefinierten Werte für seine Eigenschaften instanziieren.Erstellen Sie QML-Objekt aus C++ mit angegebenen Eigenschaften

Zum Beispiel ich schaffe eine etwas SplitView von C++ wie folgt geändert:

QQmlEngine* engine = QtQml::qmlEngine(this); 
QQmlComponent splitComp(engine, QUrl("qrc:/qml/Sy_splitView.qml")); 
QObject* splitter = splitComp.create(); 

splitter->setProperty("orientation", QVariant::fromValue(orientation)); 

Das Problem, das ich habe ist, dass die orientation des SplitViewnach Angabe es instanziiert wird bewirkt, dass es interne Layout zu brechen . Also, gibt es eine Möglichkeit, die SplitView mit der orientation bereits festgelegt zu erstellen?

Alternativ kann ich sowohl eine horizontale als auch eine vertikale Version von SplitView in separaten Dateien erstellen und die entsprechende zur Laufzeit instanziieren - aber das ist weniger elegant.

aktualisieren

I QQmlComponent::beginCreate(QQmlContext* publicContext) gefunden:

QQmlEngine* engine = QtQml::qmlEngine(this); 
QQmlComponent splitComp(engine, QUrl("qrc:/qml/Sy_splitView.qml")); 
QObject* splitter = splitComp.beginCreate(engine->contextForObject(this)); 

splitter->setProperty("orientation", QVariant::fromValue(orientation)); 
splitter->setParent(parent()); 
splitter->setProperty("parent", QVariant::fromValue(parent())); 
splitComp.completeCreate(); 

Aber es hatte überraschend keine Wirkung.

+0

Ich wette, die Sache ist in wie Sie versuchen, die Enum über QVariant zuweisen (Enums sind etwas fehlerhaft in QML). Ich würde versuchen, zuerst einen einfachen QObject-basierten Typ und eine benutzerdefinierte Enumeration zu registrieren und zu überprüfen, ob das Ganze überhaupt funktioniert.[Bitte beachten Sie, dass Sie anscheinend versuchen, Eltern zweimal zu setzen, aber das ist geringfügig] – mlvljr

+0

Ich wusste das nicht über Enums, also danke, ich werde es versuchen. Und ich setze den Elternteil nicht zweimal, setze zuerst das Elternobjekt 'QObject' und dann QML visuelle Elternsekunde (wenn ich das' QObject' Elternteil über QML setzen könnte, hätte ich mich überhaupt nicht mit C++ beschäftigt). – cmannett85

+0

Richtig, in der Tat; Anstatt den QObject-Parent zu setzen, könnte man Speicherbesitz (oder wie auch immer er aufgerufen wird) auf QmlOwnership setzen, so glaube ich (so dass das neu erstellte Objekt bei Bedarf von der QML-Laufzeit abgeführt/ref-gezählt wird). Übrigens, müssen Sie das QObject-Parent speziell aus anderen Gründen als der Speicherverwaltung setzen? – mlvljr

Antwort

0

Ich denke, Sie sollten eine benutzerdefinierte QQmlIncubator und die QQmlComponent::create(QQmlIncubator & incubator, QQmlContext * context = 0, QQmlContext * forContext = 0) Factory-Methode verwenden können.

Insbesondere unter Angabe von the QQmlIncubator documentation:

Leere QQmlIncubator :: setInitialState (QObject * Objekt) [virtual protected]

aufgerufen, nachdem das Objekt erstellt wird, aber bevor Eigenschaft Bindungen ausgewertet und ggf. wird QQmlParserStatus :: componentComplete() aufgerufen. Dies entspricht dem Punkt zwischen QQmlComponent :: beginCreate() und QQmlComponent :: endCreate() und kann verwendet werden, um den Eigenschaften des Objekts Anfangswerte zuzuweisen.

Die Standardimplementierung tut nichts.

0

Ich hatte ähnliche Situation für meine eigene QML-Komponente. Ich wollte nur ein paar Requisiten initiieren, bevor ich ein paar Bindings starte. In der reinen QML tat ich es so:

var some = component.createObject(this, {'modelClass': my_model}); 

Von C++ habe ich versucht, auf diese Weise:

// create ui object 
auto uiObject = qobject_cast<QQuickItem*>(component.beginCreate(ctx)); 
// place on ui 
uiObject->setParentItem(cont); 

// set model properties 
classInstance->setView(QVariant::fromValue(uiObject)); 
classInstance->setPosition(QPointF(x, y)); 

// set ui object properties 
uiObject->setProperty("modelClass", QVariant::fromValue(classInstance.get())); 

// finish 
component.completeCreate(); 

aber ich hatte Bindefehler, weil modelClass null bleibt! Nachdem ich eine Weile gegraben hatte, fand ich die Ursache. Und es sieht vernünftig für mich aus. Ich habe meine QML-Klasse geändert!

Item { 
    id: root 
    // property var modelClass: null 
    property var modelClass // just remove : null! 
} 

Eigenschaften mit Anfangswerte direkt nach beginCreate Aufruf nicht sichtbar sind C++, bis ich completeCreate() aufrufen. Aber wenn ich Anfangswert Eigenschaft entfernen wird sichtbar und ich kann es initialisieren in C++ Code

Verwandte Themen