QML learning curve

Dirk Hohndel dirk at hohndel.org
Sun Jan 3 11:00:31 PST 2016


Hi Willem,

I'm obviouslt not the QML expert. Or the C++ expert. But while the actual
experts are frolicking in the sun (or the snow, depending on whether they
are in the Southern or Northern hemisphere), I'll give it my best shot.

On Sun, Jan 03, 2016 at 06:21:49PM +0200, Willem Ferguson wrote:
> I am starting to gear up to make a contribution to part of the QML UI of
> Subsurface-mobile. This is my first exposure to Qt and QML, and the learning
> curve is pretty steep, augmented by the fact that I cannot find a
> comprehensive reference manual. For instance when trying to find out what
> the textRole of a QML element should contain there is only cursory mentions
> of this in the documentation that I looked at and nothing that is worth
> using.
> 
> Attached are three files on which I would really appreciate comment, two QML
> and one C++. Please look at the C++ file first, then look at view.qml.
> Basically I take a StringList and pass it from C++ to QML. Then I display
> the stringlist as elements of a list view and also in a ComboBox in QML.
> Lastly I attempt to send a signal from QML directed at a slot in the C++
> code and, within C++, print out the message associated with the signal from
> QML. I made extensive comments and discussion in the code. If anyone is
> prepared to comment or give advice I would appreciate it immensely.
> Kind regards,
> willem
> 

> #include <QGuiApplication>
> #include <QStringList>              // Objectives of this code:
>                                     // 1) Create a QStringlist and expose it to QML.
> #include <qqmlcontext.h>            // 2) Execute the QML
> #include <qqml.h>                   // 3) Listen for a signal from the QML button and print it to console (qDebug)
> #include <QtQuick/qquickitem.h>
> #include <QtQuick/qquickview.h>
> #include <QStringListModel>
> #include <QQmlApplicationEngine>
> 
> 
> class MessageClass : public QObject {   // Create a custom class to create a slot to receive messaging from QML to C++
>     Q_OBJECT
>     public slots:                       // I get compilation error: "undefined reference to vtable for MessageClass" Huh??

How about adding a constructor? Maybe that helps. This is one of those
completely incomprehensible C++ error messages that the C++ fanboys keep
saying makes "perfect sense".

>         void ButtonSlot(const QString &msg1) {      // Is this the most efficient way to do this?
>             qDebug() << "C++ called by:" << msg1;
>         }
> };
> 
> 
> int main(int argc, char ** argv)
> {
>     QGuiApplication app(argc, argv);
> 
>     QStringListModel vendorModel;           // Create a QStringList to hold names of dive computers
>     QStringList dataList;
>     dataList.append("Suunto");
>     dataList.append("Mares");
>     dataList.append("Scubapro");
>     dataList.append("Cressi");
>                                             //  I create a model, but do not use it.
>     vendorModel.setStringList(dataList);    //  The setContextProperty below uses the QStringList, not the model.
>                                             //  What is the most efficient way to expose the QStringList as a QML model?

Why aren't you using the model?

>     QQuickView view;
>     QQmlContext *ctxt = view.rootContext();
>     ctxt->setContextProperty("vendorModel", QVariant::fromValue(dataList));
>     view.setSource(QUrl("qrc:view.qml"));
>                                                 // Signalbutton is supposed to point to signalButton in the QML.
>     QObject *signalButton = view.rootObject();  // I doubt whether this is the right way to do it.
>                                                 // I would appreciate comment on this point.

I don't think this is how this works - I'll admit I'm totally clueless but
I always do it the other way around... I expose C++ stuff into QML (look
what we do with the QMLManager class)

>     MessageClass ButtonMessage;
>     QObject::connect(signalButton, SIGNAL(buttonSignal(QString)),
>                       &ButtonMessage, SLOT(ButtonSlot(QString)));
>                                                 // This is supposed to connect the QML signal to the C++ slot.

Hmm - again, the way I would have done it I would have exposed your
MessageClass to QML and then just called the slot - just like we call the
various slots of manager from QML today

>     view.show();
>     return app.exec();
> }

> import QtQuick 2.0
> import QtQuick.Controls 1.0
> 
> Rectangle {
>     width: 300; height: 300
> 
>     Item { width: 5; height: 5 }
> 
>     ListView {
>         width: 100; height: 100         // This executes correctly, shows QStringList.
>         model: vendorModel              // I conclude that the QML can correctly see
>         delegate: Rectangle {           // the C++ QStringList and that this part is
>             height: 20                  // done correctly in C++.
>             width: 100
>             Text { text: modelData }
>         }
>     }       // ListView

Cool

>     Text { x: 5; y: 100; text: "Vendor" }
> 
>     ComboBox {
>             x: 5;  y: 120               // This does NOT show the same QStringList above
>             id: vendorBox               // It sees four items that are empty.
>             model: vendorModel          // I suspect the textRole is specified incorrectly.
>             textRole: "modelData"       // I cannot find any documentation on what exactly QtQuick
> //          textRole: "display"         // roles are and how they should be specified. :-( If I have a
>     }                                   // QStringList with named fields, and I use the name of a named field,

No clue at all :-(

>                                         // then the data are shown correctly. (See tst.qml, attached)).
>     Button {
>         id: signalButton
>         signal buttonSignal(string msg1)
>         x:20; y: 200; width: 100; height: 20; text: "Send signal"
>         onClicked: {
>             buttonSignal("Button-signal")   // By hitting this button, a signal should be sent to C++
>                                             // that, in turn, prints the message on the console/terminal.
>         }                                   // Eventually I want to use this with the OnIndexChanged
>     }                                       // property of the Combobox, above.
>                                             // I have no evidence that the present code is correct.

See above. You could easily just call the slot if you expose that object
to QML

> 
> }   // Rectangle

> import QtQuick 2.3
> import QtQuick.Controls 1.4
> 
> Rectangle {
>     width: 200; height: 100; color: "#cccccc"
> 
>     ListModel {
>         id: dc_NameModel
>         ListElement { dcname: "Suunto";  d_use: "tec" }
>         ListElement { dcname: "Mares" ;  d_use: "tec" }
>         ListElement { dcname: "Scubapro";  d_use: "OW" }
>         ListElement { dcname: "Cressi";  d_use: "OW"  }
>         ListElement { dcname: "Shearwater"; d_use: "OW"  }
>     }
> 
>     CheckBox {
>         x: 1; y: 45
>         id: chkPlatformAutoRepeat
>         text: ""
>     }
>     Text {
>         id: dcText
>         x: 20
>         y: 10
>         text: "Divecomputer type"
>     }
> 
>     ComboBox {                          // This correctly displays the dc names in the listmodel defined above.
>         id: dcMakeBox                   // Note the textRole value. No other textRole value works.
>         x: 20; y: 30; width: 150
>         model: dc_NameModel
>         textRole: "dcname"
>         onCurrentIndexChanged: console.debug((dcMakeBox.currentIndex+1)+" "+dcMakeBox.currentText)
>     }

Again, no idea

Thanks for working on this, Willem. I'll agree with you, the state of QML
documentation is horrible and the available tutorials are useless. And
when you ask a question on the Qt "interest" mailing list, you get either
no answers or answers about something that is slightly related to what you
are asking and that someone knows how to do...

It's quite frustrating, TBH.

/D


More information about the subsurface mailing list