Use a c++ class as singleton inside qml files



  • Hello I have the following question:

    I have a C++ class called MyClass
    I declared the class with the following macro at the end of the MyClass.h header file:

    @
    QML_DECLARE_TYPE(MyClass)
    @

    In the main application main.c file I have the following line:

    @
    qmlRegisterType<MyClass>("MyLibrary", 1, 0, "MyClass");
    @

    then I have three different QML files
    1 - first file is MyClassAdaptor.qml and it declares the instance of the MyClass like this:

    @
    Rectangle {

        MyClass {
                     id: myClassID
                     ...
        }
    

    }
    @

    2&3 - the second and third files both declare the MyClassAdaptor object like this:
    file2:

    @
    Rectangle {
    MyClassAdaptor {
    ...
    }
    }
    @

    file3

    @
    Rectangle {
    MyClassAdaptor {
    ...
    }
    }
    @

    When starting this application, I noted that my MyClass constructor is called twice, leading to two different instances of the same C++ MyClass object.
    What I am trying to do is to have only one instance of the MyClass object.

    I know one way is to implement a singleton class pattern directly in C++, but I was wondering if there were another option to achieve this, that would only have impact in the QML files. I would not like to be obliged to modify the C++ file at all. If somebody has got any solution to perform this only by modifying the QML files, your help would be greatly appreciated.

    Further, I would also like to implement a mechanism in QML only to be able to know how many and which QML objects are currently declaring the instance of MyClass so as to be able to manage the number of signals potentially being sent to the different QML object implementing the MyClassAdaptor file.

    Thank you for your answer,
    Bill

    [EDIT: code formatting, please wrap in @-tags, Volker]



  • Very interesting question.. I am not sure how to do it in qml only.. but I had faced similar problem before and this is how I solved it..

    I created an instance of MyClass in my c++ and exported it as a property to qml with

    @QmlApplicationViewer viewer;
    MyClass tempClass; // my c++ class
    QDeclarativeContext * context = viewer.rootContext();
    context->setContextProperty("objectQml",&tempClass);@

    In all the places you want to have single object, you can use objectQml to set properties and make method calls.

    I am looking to know how to do it only in qml :)



  • Hello Vijay,
    thank you for your answer. I also thought of this in the beginning but then I was stuck with the signals coming from MyClass, i had no idea how to get them on the QML side, using the "onSignal" mechanism.
    Do you know if it's possible to implement in QML something like "objectQML.onSignal" inside my MyClassAdaptor.qml file?
    With the current solution it is easy to have this in MyClassAdaptor

    @
    Rectangle {
    MyClass {
    onSignal : --perform some action
    }
    @

    Now how can I achieve this with your solution? Can I declare the objectQML somewhere in my MyClassAdaptor file, and how?

    Thank you,
    Bill

    [EDIT: code formatting, please wrap in @-tags, Volker]





  • Wow.. interesting. I don't know how to do it. Let me find sometime to find out.



  • ok.. one thing you can do is to connect your MyClass's onSignal some signal in your qml code.

    @QObject * root = viewer->rootObject();
    QObject *qmlItem = obj->findChild<QObject *>("qmlItem "); // "qmlItem" is objectName of one of your qml items.
    QObject::connect(&MyClass, SIGNAL(onSignal ()),qmlItem, SIGNAL(qmlItemSignal ()));@

    try it out and let us know if this works.



  • Hello Vijay,

    Yes I kinda tested the "connect" thing and it worked, but it is not satisfying for me, as I may have multiple classes from which I will have to handle signals and link them to several different qml files, and I don't want to have all of them managed in my main.c file, at all. I would like everything to be handled in the QML part really.

    By the way, do you have a solution to create a singleton from within QML only?

    thank you,
    Bill



  • ok :). One more thought. Have your MyClass qml instance in your root class ( I mean main.qml rootitem), and have a javascript function which finds root item, and then gets your class id.

    your javascript class something like this

    @function getSingleton(var currentItem)
    {
    var parentItem = currentItem
    while(parentItem) {
    parentItem = parentItem.parent
    }
    return parentItem.mySingletonItem
    }@

    Don't know if this works, but worth giving a try.



  • Hello Vijay, thank you for your new suggestion.
    Where do I put this javascript function, and how do I declare an instance of MyClass that would be the return value of this function? I didn't understand, sorry.
    Bill



  • I will try this out and let you know if this work. I should post the complete code example in case if it works.



  • I'm trying to do it on my side in the mean time too, and try to make it make some sense to me ;)
    Thank you Vijay, I stay tuned!
    Bill



  • Got an answer from guyz @ Nokia telling me it was not a good idea in the first place, and that the singleton implementation should remain withinj the C++ code. So I think that settles it!



  • oho ok.. but whey is it not a good idea to have a singleton class in QML. Does it mean that we are not advised to have business logic in QML and move it to c++. And mostly we don't want to have singleton class for a displayable item and keeps moving it around??



  • Here is their whole answer

    "I have been thinking about this for a while, but didn't come up with a good solution. Besides, it feels wrong somehow trying to apply this OOP pattern to a declarative language like QML. There might be some tweaks in Javascript, but I would rather suggest to solve this in C++ or take a different approach. I mean even, if you would implement your declarative item as a singleton, the QML engine couldn't instantiate it, as it needs a public constructor."

    Regards,
    Bill



  • I know it's a old question but, did you tried to connect to the exported property using a Connections item ?

    @
    Connections {
    target: objectQml
    onSignal: //dosomething
    }
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.