Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert ListElement in a QML ListModel using C++?

Tags:

qt

qml

Well, i'm learning to work with QML and i have one doubt. In my example, i have a ListModel with ListElements at QML and i have a QML main file with a rectangle, PathView etc.

I have a QWidget also, than is my main window. In this QWidget i include the QML UI like a component. Ok!

How can I handle QML ListElements by using C++?
Note: when I say "to handle", I want to say include an element for example.

Below are some parts of my code...

QML containing my ListElement, called "Menu1":

import QtQuick 1.0

ListModel {
    id: listMovieModel
    ListElement { name: "Image 1"; iconSource: "pics/image_1.jpg" }
    ListElement { name: "Image 2"; iconSource: "pics/image_2.jpg" }
    ListElement { name: "Image 3"; iconSource: "pics/image_3.jpg" }
    ListElement { name: "Image 4"; iconSource: "pics/image_4.jpg" }
    ListElement { name: "Image 5"; iconSource: "pics/image_5.jpg" }
    ListElement { name: "Image 6"; iconSource: "pics/image_6.jpg" }
}

My main QML:

Rectangle {
    width: 500
    height: 600
    color: "transparent"

    PathView {
        id: view
        focus: true
        width: parent.width
        height: parent.height + y
        y: -150
        model: Menu1 {} //First QML showed
        delegate: Image {
            source: iconSource
            width: 64
            height: 90
            scale: PathView.isCurrentItem ? 3.5 * y / parent.height : 2.0 * y / parent.height
            z: y
            smooth: true
        }
        path: MyGeometricFigure { //This a another file, but is confidential
            width: view.width
            height: view.height
        }
        preferredHighlightBegin: 0
        preferredHighlightEnd: 0
        highlightRangeMode: PathView.StrictlyEnforceRange
        Keys.onLeftPressed: decrementCurrentIndex()
        Keys.onRightPressed: incrementCurrentIndex()
    }
}

And as I use QML like a component for my QWidget:

MainForm::MainForm(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainForm)
{
    ui->setupUi(this);
    this->resize(1024, 576);

    QDeclarativeView *myQMLTest = new QDeclarativeView(QUrl::fromLocalFile("myMainQML.qml"));
    myQMLTest->setStyleSheet(QString("background: transparent; width: 600px"));

    this->ui->frameListVideoGallery->layout()->addWidget(myQMLTest);
    myQMLTest->setFocus();
    myQMLTest->installEventFilter(this);
}

I saw some articles about this, but I am not able to change my LisModel using C++. I saw here http://doc.qt.nokia.com/4.7/qdeclarativemodels.html#c-data-models and here in examples using PathView http://doc.qt.nokia.com/4.7/qdeclarativeexamples.html

Can someone help me?

Thanks!

like image 933
Adriano Leal Avatar asked Feb 02 '12 19:02

Adriano Leal


2 Answers

Alright. I think you can do something like this:

In your main QML-file add simple function.

Rectangle {
    // ...

    function append(newElement) {
        view.model.append(newElement)
    }

    PathView {
        id: view

        // ...

        model: Menu1 {} //First QML showed

        // ...
    }
}

This method will just call a corresponding method from ListModel. More supported methods you can find there.

Then all you need is to call this method from C++ code. You can do this in such manner:

MainForm::MainForm(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainForm)
{
    ui->setupUi(this);
    this->resize(1024, 576);

    QDeclarativeView *myQMLTest = new QDeclarativeView(QUrl::fromLocalFile    ("myMainQML.qml"));
    myQMLTest->setStyleSheet(QString("background: transparent; width: 600px"));

    QVariantMap newElement;  // QVariantMap will implicitly translates into JS-object
    newElement.insert("name",       "Image 13"         );
    newElement.insert("iconSource", "pics/image_13.jpg");

    QMetaObject::invokeMethod(
        myQMLTest->rootObject(),                          // for this object we will call method
        "append",                                         // actually, name of the method to call
        Q_ARG(QVariant, QVariant::fromValue(newElement))  // method parameter
    );

    this->ui->frameListVideoGallery->layout()->addWidget(myQMLTest);
    myQMLTest->setFocus();
    myQMLTest->installEventFilter(this);
}

You should check this for more information.

Also you can choose another approach: to pass some data via qml properties (using QDeclarativeEngine and QDeclarativeContext) and then handle this data and your list-model right in JavaScript code.

like image 128
GooRoo Avatar answered Oct 13 '22 04:10

GooRoo


I want to make the answer from @GooRoo more complete/usefull to Qt beginners. If you use the Qt Creator, you will start with a template using QmlApplicationViewer. To apply the answer from GooRoo you have to do something like this (thanks to http://www.lothlorien.com/kf6gpe/?p=309):

CPP:

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> app(createApplication(argc, argv));
    QScopedPointer<QmlApplicationViewer> viewer(QmlApplicationViewer::create());

    viewer->setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer->setMainQmlFile(QLatin1String("qml/mydemo/main.qml"));
    viewer->showExpanded();

    QMetaObject::invokeMethod(
        (QObject *)viewer->rootObject()->findChild<QObject *>("myModel"), // QML item
        "test"                           // name of the method to call
                                         // without parameters
    );

    return app->exec();
}

QML:

PageStackWindow {
    id: mainApp
    ...

    ListModel {
        id: myModel
        objectName: myModel //THIS IS NEEDED BY findChild()
        ...
        function test() {
            console.log("TEST OK");
        }
    }

    Page {
        ...
    }
}
like image 27
meolic Avatar answered Oct 13 '22 05:10

meolic