2
votes

SOLVED: I did everything like eyllanesc answer and in my FirstPage.qml inside delegate where i access model data i put modelData before names. Previously inside FirstPage.qml delegate i used: name, completed and uncompleted and now i use modelData.name, modelData.completed and modelData.uncompleted. It is all fine now.

I'm completely new in the QT/QML and I tried but could not find an answer for my problem.

I use model (created in c++) in QML. When app starts everything is fine but when i try to add new element to model it is not displayed in QML. Model is the same like from the start.

I have class modcontroller and inside it i create list.

modcontroller.h

#ifndef MODCONTROLLER_H
#define MODCONTROLLER_H

#include <QObject>
#include <list.h>

class modcontroller : public QObject
{
    Q_OBJECT

public:
    explicit modcontroller(QObject *parent = nullptr);

    QList<QObject*> getList();

    Q_INVOKABLE void addList(QString nam);

signals:
    void listChanged();

public slots:

private:
    QList<QObject*> m_dataList;
};

#endif // MODCONTROLLER_H

modcontroller.cpp

#include "modcontroller.h"
#include <QDebug>

modcontroller::modcontroller(QObject *parent) : QObject(parent)
{
    m_dataList.append(new List("Test"));
}

QList<QObject *> modcontroller::getList()
{
    return m_dataList;
}

void modcontroller::addList(QString nam)
{
    m_dataList.append(new List(nam));
    qDebug() << "Function addList called";

    qDebug() << m_dataList;
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "list.h"
#include "modcontroller.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);


    QQmlApplicationEngine engine;


    modcontroller controller;
    engine.rootContext()->setContextProperty("myModel", QVariant::fromValue(controller.getList()));
    engine.rootContext()->setContextProperty("controller",&controller);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;



    return app.exec();
}

In QML file i have ListView with model: myModel, and button with

onClicked: {
                controller.addList(textInput.text)
                myStackView.push(firstPage)
            }

When i click create i see only the first item "Test" that is created in the start but in the console i get this:

Function addList called
(List(0x2b7e60bc2c0), List(0x2b82d5891b0))

Thanks in advance.

main.qml

    ApplicationWindow {
        visible: true
        width: 580
        height: 360
        title: qsTr("Hello World")

        StackView{
            id: myStackView
            initialItem: firstPage
            anchors.fill: parent
        }

        Component{
            id: firstPage
            FirstPage{}
        }

        Component{
            id: createNewListPage
            CreateNewListPage{}
        }

    }

FirstPage.qml

Item {    
    ListView{
                id: lists
                width: 150
                height: childrenRect.height
                x: 15
                y: 70

                model: myModel

                delegate: Row{
                    width: 150
                    height: 25
                    spacing: 5

                    Rectangle{
                        width: {
                            if(uncompleted < 3){return 3;}
                            else if(uncompleted < 6){return 6;}
                            else {return 10;}
                        }
                        height: {
                            if(uncompleted < 3){return 3;}
                            else if(uncompleted < 6){return 6;}
                            else {return 10;}
                        }
                        radius: 10
                        color: "#494949"
                        anchors.verticalCenter: parent.verticalCenter
                    }
                    Button {
                        id:button1
                        height: 23

                        contentItem: Text {
                            id: textTask
                            text: name
                            font.underline: true
                            color: "blue"
                            font.bold: true
                            font.pointSize: 10
                            height: 20
                            anchors.verticalCenter: parent.verticalCenter
                            anchors.left: parent.left
                        }

                        background: Rectangle {
                            id: rectangle
                            color: "transparent"
                        }
                        states:[
                            State {
                                name: "Hovering"
                                PropertyChanges {
                                    target: textTask
                                    color: "white"
                                    font.bold: true
                                    font.underline: false
                                }
                                PropertyChanges {
                                    target: rectangle
                                    color: "blue"
                                }
                            }]

                        MouseArea{
                            hoverEnabled: true
                            anchors.fill: button1
                            onEntered: { button1.state='Hovering'}
                            onExited: { button1.state=''}
                        }
                    }
                    Text{
                        font.pointSize: 8
                        text: {
                            if(uncompleted == 0)return "";
                            return "- " + uncompleted + " left";
                        }
                        color: "#494949"
                        anchors.verticalCenter: parent.verticalCenter
                    }
                }
            }
}

CreateNewListPage.qml

Item {
   Rectangle{
       width: 580
       height: 360

       Rectangle{
        width: 350
        height: 30
        y: 100
        x: 30
        border.color: "#7b9cd3"
        border.width: 1

        TextInput {
            id: textInput
            anchors.topMargin: 3
            cursorVisible: true
            anchors.fill: parent
            font.bold: true
            font.pointSize: 14
        }

    }



       Button{
                height: 20
                text: "Create this list"
                onClicked: {
                    controller.addList(textInput.text)
                    myStackView.push(firstPage)
                }

                background: Rectangle{
                    id: rect1
                    anchors.fill: parent
                    radius: 20
                    border.color: "#88b6cf"
                    gradient: Gradient {
                            GradientStop { position: 0.0; color: "#fcfefe" }
                            GradientStop { position: 1.0; color: "#d5e8f3" }
                    }
                }

            }

     }
}
1
i added my qml files and type List is class with QString and two integers. I use them in FirstPage.qml file like name, completed, uncompletedpeco

1 Answers

0
votes

The lists are a dummy model because by itself it does not notify the view if there is any change such as the number of elements, so a solution for your case is to make it a mod_controller's Q_PROPERTY, then when you add an item, the sign listChanged that will notify the view that something has changed and therefore needs to be repainted. It is not necessary to export the list separately from the controller since the Q_PROPERTY are accessible in QML, so the solution is:

modcontroller.h

#ifndef MODCONTROLLER_H
#define MODCONTROLLER_H

#include <QObject>

class modcontroller : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject *> lists READ getList NOTIFY listsChanged) // <---
public:
    explicit modcontroller(QObject *parent = nullptr);
    QList<QObject *> getList() const;
    Q_INVOKABLE void addList(const QString &nam);
    Q_SIGNAL void listsChanged();
private:
    QList<QObject*> m_dataList;
};

#endif // MODCONTROLLER_H

modcontroller.cpp

#include "modcontroller.h"
#include "list.h"

#include <QDebug>

modcontroller::modcontroller(QObject *parent) : QObject(parent)
{
    m_dataList.append(new List("Test"));
}

QList<QObject *> modcontroller::getList() const
{
    return m_dataList;
}

void modcontroller::addList(const QString & nam)
{
    m_dataList.append(new List(nam));
    qDebug() << "Function addList called";
    qDebug() << m_dataList;
    Q_EMIT listsChanged(); // <---
}

main.cpp

#include "modcontroller.h"

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    modcontroller controller;
    engine.rootContext()->setContextProperty("controller",&controller);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

In the case of QML, the binding is done with the Q_PROPERTY list of controller:

ListView{
    // ...
    model: controller.lists // <---
    // ...