[SOLVED] Beginner: How to use Qt and C++ the right way?



  • Hello

    My background is mostly .NET. My c++ Skills are not (yet) that great and i'm pretty much new to Qt.
    I was reading many tutorials and posts about using QML2 and C++ together. I was however unable to find the right entrance to the Topic.

    So in .NET there is the GUI-code file and the .NET code file. Which both know pretty much anything about each other and can easly be instantiated. This easy approach is a thing i'm still looking for for Qt.

    I know how i can create a c++ class, inerhiting from QObject and exposing its Properties and Methods so it can be used from within QML. This however is an approach from the opposite side.
    My C++ code should show the GUI and not the GUI should load the C++ code.

    What my program is intended to do:

    • running headless (no main window)
    • managing different undecorated windows. All of which implementing the same interface to display some content (videos, pictures, etc..)
    • windows talk with program (bi-directional)

    Pseudo program:
    start.mainloop()
    create.windows()
    connect(signals from windows)
    show/hide.specific(window)
    send.data(toWindow) // properties/

    -> instantiating c++ class should create new GUI.qml
    -> c++ should be able to set/get properties from the gui.qml
    -> qml calls signals from c++

    If anyone could provide me with some sample code of the files necessary this would be great. I need the complete code because its always hard for me to find the correct imports.

    Thanks, Archdove

    Edit:
    Qt5.0/Qml2.0/Archlinux



  • Helo. Short answer: this is not how QML is intended to work.

    The classic Qt Widgets serve better for your .Net analogy. There you have the UI widgets which are C++ objects. The widgets drive your code by means of signals and slots (just like events and delegates in .Net). The code can in turn directly drive the widgets, by means of setting properties or calling methods on them. However there are Qt classes that separate business logic from presentation logic (the model/view classes, eg. QAbstractItemModel vs. QListView), it is very easy to get the (widget) UI code very tighly coupled with business logic.

    QML on the other hand encourages further (I would even dare to say real) separation of presentation code. Mixing C++ and QML is intended this way:

    • you can write your application / business model by means of C++/Qt objects. Define well the methods and properties of your business objects. Then expose them to the QML presentation layer.
    • in your QML, consume the model, visualize it, or provide controls to modify it by calling the exposed methods.

    The point is, your C++ code (the business end) should know nothing about the QML code (the front end). One of the reason is, that the QML may change any time, i.e. a designer decides that she removes a button from one screen and places it in another screen (decoupling of UI design process from SW business implementation).

    Put another way: the C++ business model drives the presentation layer indirectly by means of updating properties of the exposed objects. While it is totally possible to modify QML directly from C++, it is considered bad practice. Even the code to do that is very awkward.

    This presentation catches nicely the point: http://www.youtube.com/watch?v=Y1pqL5bXe0A



  • Thanks Martin for your response.

    The thing is, the intended application is a multimedia application which should be nice to look at. One wont see any real GUI elements because they're only used to put the content on screen. This howerver should be done nicely.
    Therefore i seek the smooth animations QML provides. One window can change its content between Pictures, HTML and Videos which should be done without anything flickering.
    As i understand, QML is fully accelerated and QWidgets are not?

    Your point saying that QML should merely consume the model is easly addressed. I would have a content class with say, a mime type and therefore QML knows what to do.
    So what i don't see is how i can "expose" an object to an already existing qml gui (window).

    Isn't QML replacing the whole Qt Widget approach?
    Is it possible to show a QML element inside a Qt Widget?

    How about Qt Widgets on Android? I know QML is coming but what about the Widgets?

    And thanks for the link. I will watch it.
    -> The video is good but it did not really clear up much. It just shows the "qml in the center" approach i already know.

    I have found a pretty good post about this: http://blog.qt.digia.com/blog/2012/04/18/qt-5-c-and-qt-widgets/
    But i still beleve i'm on the right track. Since Widgets are described as the old "static" gui and qml the new animated ones.



  • QML does not replace the widgets UI paradigm, but rather complements it. QML is more suited for touch based fluid UIs. Qt5 is going to support many touch platforms, therefore it puts much emphasis on QML nowadays. Widgets are still available in Qt5 and are going to be supported on Android (AFAIK, and iOS as well).

    Widgets are always drawn using the CPU. QML in Qt 4 (also called Qt Declarative or Qt Quick 1) is optionally accelerated (but not by default). The newer version (called Qt Quick 2) in Qt 5 is built on top of an OpenGL scene graph and therefore always fully accelerated. If your platform does not support at least OpenGL 2.0 or ES 2.0, Qt Quick 2 will not work there.

    Yes, you can display QML content in widgets. In Qt 4 you display QML inside a QDeclarativeView which itself is a QWidget, so you can embed it in your widget UI layout or use as standalone window. In Qt 5 it's little bit more complicated - QML is displayed in QQuickView window which is not a widget but rather an accelerated open GL surface. It can be used in widget UI as well via a proxy widget called a window container (this feature has actually yet to come with Qt 5.1).

    The actual exposing of your model to QML is best shown in code:

    @class MyModel : public QObject { /* ... */ };
    ...
    QQuickView view;
    view.rootContext()->setContextProperty("model", new MyModel);
    view.setSource(QUrl::fromLocalFile("yourQml.qml"));
    view.show();
    @

    For complete overview on interaction between C++ and QML look at this page - http://qt-project.org/doc/qt-4.8/qtbinding.html the article is targeted for Qt 4 but exactly the same mechanisms work in Qt 5 only some class names are different (eg. QDeclarative* becomes QQuick* in Qt5).



  • Hi there

    Thanks again for your response. Thanks to your post i found this great article which explains things in Qt5.

    http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-interactqmlfromcpp.html

    With this i tried writing some code. I'm fully able to load, show and alter qml classes using QQuickView. If is use QQmlEngine and Component however, i'm not able to show the gui.

    [code] QGuiApplication app(argc, argv);

    QQmlEngine engine;
    QQmlComponent component(&engine,
            QUrl::fromLocalFile("qml/interaction2/main.qml"));
    QObject *object = component.create();
    
    QQmlProperty(object, "widht").write(600);
    QQmlProperty(object, "height").write(600);
    
    QQuickItem *item = qobject_cast<QQuickItem*>(object);
    item->setVisible(true);
    item->setOpacity(100);[/code]
    

    I know that at some point i should delete object again. That does not matter at this point.
    My question is about what the actual difference is between QQuickView and QQmlComponent. If there is no big difference betweene them i can just use the View. The Windows however should only show when i want them to do so.
    => OK i got it. Using QtQuick.Window 2.0 in QML while casting to a QQuickWindow in C++ does the trick!

    Could not yet look into the rootContext thing. Is it usable for both, View and Component?



  • Although the usage is similar, there is a big conceptual difference between QQmlComponent and QQuickView.

    QQmlComponent represents a QML type (a "class" if you will, defined in QML language). The C++ QQmlComponent allows you to load a QML type and instantiate it by calling the create() method. Your QML component instance then starts its life inside a QQmlContext. The root context comes from the qml engine. The context is sort of a container where QML objects live. And via the context, you can also inject your C++ objects which the QML object can consume by calling setContextProperty().

    Please, note that QML is not restricted to GUIs. You can absolutelly use QML for non-visuall stuff. Therefore QQmlComponent provides no view. This is where QQuickView comes in - it encapsulates the qml engine, context, loads the QML component for you and on top of that provides a window and with a "canvas" where visual items are displayed. The QQuickItem from your code cannot be displayed on its own, but through a QQuickView.

    Hope that clears that a bit.



  • ...about object deletion and ownership, there is a rule of thumb:

    • if the object was created by the QML runtime (by QQmlComponent or QQuickView) it is owned by the QML runtime and it manages the object's lifetime.
    • if you created the object in C++ (i.e. called operator new) and then exposed the object to QML via QQmlContext::setContextProperty() then you are still responsible for its lifetime and should delete it eventually.


  • Thanks. Its pretty much clear to me now. Not to whole context stuff but i got a general idea and the interaction progresses well.

    Right now i try to display a video inside qml. I am hoping to get this to work by the evening.
    C++ sets source via property (no problem), qml signals the end of file when reached the video end.

    For now, the video does not show with no error. It works in mplayer and i've installed gstreamer with all the plugins i could find. When starting i had a message about missing gst plugins.

    So thanks for all the help. You ensured a good start for me.

    Since this topic is generally solved, should i mark it as such in any way?


Log in to reply
 

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