2

I just started learning Qt. To be honest, some of confuses my a lot. I'm trying to load a predefined .csv table into a listview. I created a qml file with the simple layout of a textfield, a listview and a button to load a file. The file looks like this:

import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2

ApplicationWindow {
    id: applicationWindow
    objectName: "App"
    visible: true
    width: 640
    height: 480
    title: qsTr("Rosinenpicker")

    ColumnLayout {
        id: columnLayout
        anchors.rightMargin: 40
        anchors.leftMargin: 40
        anchors.bottomMargin: 40
        anchors.topMargin: 40
        anchors.fill: parent


        TextField {
            id: name
            text: qsTr("Text Field")
            Layout.preferredHeight: 50
            Layout.fillWidth: true
        }

        ListView {
            id: list
            x: 0
            y: 0
            width: 110
            height: 160
            spacing: 0
            boundsBehavior: Flickable.DragAndOvershootBounds
            Layout.fillHeight: true
            Layout.fillWidth: true
            objectName: "listView"
            model: guestModel

            delegate: Item {
                x: 5
                width: 80
                height: 40

                Text {
                    text: model.modeldata.name
                    font.bold: true
                    anchors.verticalCenter: parent.verticalCenter
                }
            }
        }

        Button {
            id: button
            width: 50
            text: qsTr("Open File")
            Layout.preferredWidth: 100
            Layout.alignment: Qt.AlignRight | Qt.AlignVCenter

            onClicked: fileDialog.visible = true;
        }

        FileDialog {
            id: fileDialog
            title: "Please choose a valid guestlist file"
            objectName: "fileDialog"
            nameFilters: ["Valid guestlist files (*.csv)"]
            selectMultiple: false

            signal fileSelected(url path)

            onAccepted: fileSelected(fileDialog.fileUrl)
        }
    }
}

In my main file I create a CsvParser class a connect it to the fileSelected signal of the file dialog. I can parse the csv-File. But when I try to connect it to the listview, I'm lost.

The main file:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtDebug>
#include <QUrl>
#include <QQuickView>

#include "csvparser.h"

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

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

    auto root = engine.rootObjects().first();
    auto fileDialog = root->findChild<QObject*>("fileDialog");

    CsvParser parser(engine.rootContext());
    QObject::connect(fileDialog, SIGNAL(fileSelected(QUrl)), &parser, SLOT(loadData(QUrl)));

    return app.exec();
}

My parser looks like this:

#include "csvparser.h"

#include <QtDebug>
#include <QFile>

#include "guest.h"

CsvParser::CsvParser(QQmlContext *context)
{
    this->context = context;
}

void CsvParser::loadData(QUrl path)
{
    friendList.clear();
    guestList.clear();

    QFile file(path.toLocalFile());
    file.open(QIODevice::ReadOnly);

    // ignore first lines
    for(int i=0; i<3; i++)
        file.readLine();

    while(!file.atEnd()) {
        auto rowCells = file.readLine().split(',');

        if(rowCells.size() != 6)
            continue;

        checkedAdd(friendList, rowCells[0], rowCells[1]);
        checkedAdd(guestList, rowCells[3], rowCells[4]);
    }

    qDebug() << guestList.size();
    auto qv = QVariant::fromValue(guestList);
    context->setContextProperty("guestModel", qv);
}

void CsvParser::checkedAdd(QList<QObject*> &list, QString name, QString familyName)
{
    if(name == "" && familyName == "")
        return;

    list.append(new Guest(name, familyName));
}

And the guest, which has only a name and a familyname looks like this:

#ifndef GUEST_H
#define GUEST_H

#include <QObject>

class Guest : public QObject
{
public:
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString fName READ fName WRITE setfName NOTIFY fNameChanged)

public:
    Guest(QString name, QString fName);

    QString name();
    QString fName();

    void setName(QString name);
    void setfName(QString fName);

signals:
    void nameChanged();
    void fNameChanged();

private:
    QString m_name, m_fName;
};

#endif // GUEST_H

I get the following output:

qrc:/main.qml:41: ReferenceError: guestModel is not defined
QFileInfo::absolutePath: Constructed with empty filename
2
qrc:/main.qml:49: TypeError: Cannot read property 'name' of undefined
qrc:/main.qml:49: TypeError: Cannot read property 'name' of undefined

What am I doing wrong? Any help is appreciated. Thanks!

1
  • Hard to say more than the errors say. Did you try to fix the errors? The first one is that guestModel is not defined, you need to define it. I would recommend using QAbstractListModel for that. Commented Jun 13, 2017 at 13:57

1 Answer 1

1

There are a few things I think are wrong. QML will not find guestModel, because it tries to render the ListView but it has not been made available to QML since you are setting the context property in loadData(), which is however only invoked when the user interacts with the FileDialog. Also, the Q_OBJECT macro needs to appear in the private section of the class (see http://doc.qt.io/qt-5/qobject.html#Q_OBJECT). Also, I do not think it is nice to make a data container/parser class aware of the UI, i.e. you export the rootContext to the parser. It would be better if you export something from the parser to the rootContext in main. The parser should have no notion of the UI IMHO. Finally, if you want to implement a custom list of data items to be displayed, you really should think about using an AbstractListModel as Yuki has suggested (see, http://doc.qt.io/qt-5/qabstractlistmodel.html) or another suitable List-based model (see, http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html). This way, changes in C++ will automatically result in updates in the UI.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.