Solved Is it possible to expose a C++ Class that doesn't have a default constructor to QML ?
-
@Curtwagner1984 I just tried to pass the id as "this" pointer and it worked.
So, you register all your derived classes as usual and use them with a proper id.
The generic function takes a pointer of the base class, and you call that function with the id you issued in Qml. -
@c64zottel said in Is it possible to expose a C++ Class that doesn't have a default constructor to QML ?:
@Curtwagner1984 I just tried to pass the id as "this" pointer and it worked.
So, you register all your derived classes as usual and use them with a proper id.
The generic function takes a pointer of the base class, and you call that function with the id you issued in Qml.Can you please elaborate on what exactly you did? I'm not sure I follow. An example would be best.
-
@Curtwagner1984 Something like this:
class Base : public QObject { ... Q_INVOKABLE virtual void func(); signals: void activated(); } class D1 : public Base { void func() { do stuff; } } class D2 : public Base { void func() { do other stuff; } } class SomeClientUsingBase : public QObject { Q_INVOKABLE void functionDealingWithSomethingDerivedFromBase( Base * b ) { b->func(); // uses either D1 or D2 } }
In Qml:
qmlRegisterType<SomeClientUsingBase>("com.me.qmlcomponents", 1, 0, "Client"); qmlRegisterType<Base>("com.me.qmlcomponents", 1, 0, "Base"); qmlRegisterType<D1>("com.me.qmlcomponents", 1, 0, "D1"); qmlRegisterType<D2>("com.me.qmlcomponents", 1, 0, "D2");
Client { id: waitingToUseBase } D1 { id: d1 onActivated: waitingToUseBase.functionDealingWithSomethingDerivedFromBase( d1 ) } D2 { id: d2 onActivated: waitingToUseBase.functionDealingWithSomethingDerivedFromBase( d1 ) }
-
@sierdzio said in Is it possible to expose a C++ Class that doesn't have a default constructor to QML ?:
You can, however, add an init() function and pass your pointer there, after QML engine creates the object.
How would I go about doing this? How would I know that the object was created in QML in order to trigger the init() function?
I suppose I could connect it to a signal that is triggered by the default constructor, is that what you are suggesting?Ugh, as always with QML, there are many ways to do it and I never know which solution to recommend :D Let's try this:
// C++ // add DbManager to QML context somewhere. Example: DbManager manager; QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("Manager", &manager); [...] class BasicListModel { Q_INVOKABLE void init(DbManager *manager); } // QML [...] model: BasicListModel { Component.onCompleted: { init(manager); } }
-
This post is deleted! -
@sierdzio Thank you! It works exactly as expected.
Now I wonder, can I create an instance of BasicListModel dynamically? Something along the lines of :
function generateDynamicInstance() { // returns a new instance of BasicListModel } Button { onClicked:{ var newInstance = generateDynamicInstance(); myListView.model = newInstance; } } ListView{ id:myListView }
-
@Curtwagner1984 said in Is it possible to expose a C++ Class that doesn't have a default constructor to QML ?:
Now I wonder, can I create an instance of BasicListModel dynamically? Something along the lines of :
Yes, this page in docs describes it: link. Or you can use a Loader.
-
@sierdzio
I've already looked at the page Dynamic QML Object Creation from JavaScript ,but I thought the functionQt.createComponent()
is only for .qml files , and thecreateObject
object method only works on components created by theQt.createComponent()
method.I've tried to create a component manually like so:
Component { id: myTestComponent ActorModel { id: actModel Component.onCompleted: { console.log("ACTORMODEL:ON COMPLETE TRIGGERED") init(dbManager) } } }
and then use the
createObject
method on it like thismyTestComponent.createObject
, but it didn't complile. (Clearly, I'm doing it wrong, but I couldn't find how to use this method on a C++ registered Object in the documentation.)I did manage to use a Loader like this:
Component { id: myTestComponent ActorModel { id: actModel Component.onCompleted: { console.log("ACTORMODEL:ON COMPLETE TRIGGERED") init(dbManager) } } } Loader{ id: myTestLoader sourceComponent: myTestComponent } ListView{ id:myList model:myTestLoader.item }
But I'm unsure as to how to trigger a creation of a new instance.
-
@sierdzio I managed to get it to work with
createObject
like so:Component { id: myTestComponent ActorModel { id: actModel Component.onCompleted: { console.log("ACTORMODEL:ON COMPLETE TRIGGERED") init(dbManager) } } } Button { onClicked: { // creates a new instance of ActorModel var x = myTestComponent.createObject(); myList.model = x; } } ListView{ id:myList }
Thank you very much for your help!
-
You're welcome, happy coding :-)
And thanks for sharing the solution, maybe it will help somebody else, too.