Porting a "large" Desktop application to QML



  • Hi there,
    I ‘ve got a “large” Qt Desktop App (100+ classes) and I want to port a part of it as a mobile application.
    I’m new to QML and took a look at the documentation and the examples.
    My application uses models and controllers with the following requirements:

    • Passing and returning pointers and/or references to functions
    • Using singleton classes to store settings (like user/password)

    I also used Google to try to understand QML, but I’m still not sure if I understand the functionality.
    My resumé is:
    Returning pointers is not possible because the object is directly destroyed after the call of the function.
    Using C++ singletons is not possible (I created an instance in the main.cpp, but the instance created in the C++ function called from QML has a different address)
    Passing pointers to C++ is not that easy/possible?!?
    My summary:
    I have to write a new QML application, I can’t reuse my old code without changing it (I still need the Desktop application).
    If all this is possible: Is there a large QML/ C++ application example I haven’t found jet, I can take a look at?

    Greetings,
    Sebastian



  • Hi mate
    A few months back I had similar doubts about porting my "quite" big app from QWidgets to QML. Now I'm a bit wiser and happy QML coder.
    So as they used to say: "The worst job is that not begun one" - just start porting :-)

    I was advised to start thinking declaratively and it was important key. It is like new dimension after C++/QWidgets. But when I caught it a little, porting went faster and better.

    To got QObject derivative class as a singleton:

    // main.cpp
    // (....)
    auto e = new QQmlApplicationEngine;
    SingletonClass singleton; // create singleton object
    e->rootContext()->setContextProperty(QStringLiteral("SINGLETON"), &singleton); // then registry it for QML before main QML file is loaded
    e->load(QUrl(QStringLiteral("qrc:/MainWindow.qml")));
    a->exec();
    (....)
    

    Then, wherever in QML code:

    // SomeQMLfile.qml
    Item {
      someProperty: SINGLETON.someProperty
      otherProp: SINGLETON.someFunction()
    }
    

    This way You may wrap Your settings and expose it for QML.
    And You really do not need to have function pointers on QML side, keep them in C++ logic.
    Let's simple say: QML responses for visual side of Your app and You may reuse the rest of Your C++ code.

    Anyway, keep strong!



  • @Grisu I don't understand all you say about your needs and concerns. "Passing and returning pointers and/or references to functions" - do you mean you use functional programming or do you use callback architecture? In which direction (between UI and backend)? What do you mean by "Returning pointers is not possible because the object is directly destroyed after the call of the function"? What pointers, from where to where, and what object is destroyed?

    Why do you need a large example? I think the basics are the same no matter it's 5 or 100 classes.

    The most important thing in porting is to have a clear-cut three-tier architecture first or at least clear separation between UI and backend/business logic/data models. If your C++ UI code is separated from the backend code and the backend code knows nothing about the UI code and the UI code uses the backend code through a clear API everything should be pretty easy or at least easily solvable. QML code can use QObjects and you can exchange data by using QObject and certain basic Qt classes. Using QML and C++ together is documented in the Qt docs and isn't too difficult once you get started - the first steps are of course the most difficult and make you anxious.



  • I’m trying to be strong 😉,
    thank you for your replies.

    I threw away my QML Application and started a new one to give QML with C++ another chance.
    I think I need some vacation to learn QML. I'm not using it at work.

    The singleton problem is solved. I created it in main.cpp and forgot to call setContextProperty(…) now it is working.

    Sending back pointers is also working

    //work.h
    Q_INVOKABLE ReturnCode *checkWithReturn();
    //main.cpp works with 
    qmlRegisterType<ReturnCode>("sealsoft.returnCode", 1, 0, "ReturnCode");
    

    But I still don’t understand how to pass a pointer with a new instance to a function

    //In work.h
    Q_INVOKABLE ReturnCode *passNewUser(User *user);
    
    //In main.cpp
    qmlRegisterType<ReturnCode>("sealsoft.returnCode", 1, 0, "ReturnCode");
    qmlRegisterType<User>("sealsoft.user", 1, 0, "User");
    
    Work work;
    engine.rootContext()->setContextProperty("work",&work);
     
    //In main.qml
    var luser = new User() // This is not allowed I think 
    var lretCode2 = work. passNewUser (luser)
    

    The Problem is

    var luser = new User()
    

    If I understood the documentation correctly you can’t create a new instance in QML of a qmlRegisterType.
    A solution is writing in main.cpp.

    User user;
    engine.rootContext()->setContextProperty("user",&user);
    // and in main.qml
    user.m_name = "Name from main.qml";
    var lretCode2 = work. passNewUser (user)
    

    But if I need User in different QMLs main.h will look like:

    engine.rootContext()->setContextProperty("user",&user);
    engine.rootContext()->setContextProperty("user2",&user2);
    engine.rootContext()->setContextProperty("user3”,&user3);
    

    OK User isn't a good example it will only exist once, but there will be another class.

    Hope you can solve the mystery, I think I’m a blockead



  • Problem ist solved, I think ;-)

    main.cpp
    ...
        qmlRegisterType<User>("sealsoft.user", 1, 0, "User");
    ...
    
    qml:
        Component{
            id:myComp
            User{
                id:myUser
            }
        }
    ....
    var user = myComp.createObject();
    

Log in to reply
 

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