Bartlomiej
Bartlomiej

Reputation: 13

Is there a way to get content of ListModel from QML to pyqt?

In my TableView I have ListModel that is filled by user. I wanna save this model as a .csv file using python. But I can't send model via qml signal to pyqt (there is no type for models), and if I want to access this ListModel in python using this line.

Python

model = self.engine.rootObjects()[0].findChild(QObject, "newCsvModel")

In return I get QAbstractListModel, which (in my understanding) doesn't hold model content.

QML

This is how I use my model

TableView {
            model: ListModel{
                id: csvModel
                objectName: "newCsvModel"

                ListElement{
                    key1: "val1"
                    key2: "val2"
                    ...
                }
                ...
            }

I have a class for sending the exact type of model from pyqt to qml and it works fine, but doing it the other way around is problematic for me. Do you know how extract data from qml ListModel?

Upvotes: 1

Views: 783

Answers (1)

eyllanesc
eyllanesc

Reputation: 243975

You should not export directly to a QML object, instead use a QObject that fetches the QML object through a slot obtaining the model, accessing the roles and values to save it in a .csv.

import csv

from PyQt5 import QtCore, QtGui, QtQml


class CSVHelper(QtCore.QObject):
    @QtCore.pyqtSlot("QAbstractItemModel*", str)
    def saveListModel(self, model, filename):
        headers = {v.data().decode(): k for k, v in model.roleNames().items()}
        with open(filename, mode="w") as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=headers.keys())
            writer.writeheader()

            for i in range(model.rowCount()):
                row = dict()
                for name, role in headers.items():
                    value = model.index(i, 0).data(role)
                    row[name] = value
                writer.writerow(row)


if __name__ == "__main__":
    import os
    import sys

    app = QtGui.QGuiApplication(sys.argv)

    csv_helper = CSVHelper()

    engine = QtQml.QQmlApplicationEngine()
    engine.rootContext().setContextProperty("CSVHelper", csv_helper)
    file = os.path.join(os.path.dirname(os.path.realpath(__file__)), "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(file))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec())

main.qml

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Controls 1.4


ApplicationWindow {
    id: root
    visible: true
    width: 640
    height: 480

    ListModel {
        id: libraryModel
        ListElement {
            title: "A Masterpiece"
            author: "Gabriel"
        }
        ListElement {
            title: "Brilliance"
            author: "Jens"
        }
        ListElement {
            title: "Outstanding"
            author: "Frederik"
        }
    }
    Column{
        Button {
            text: "Press me"
            onClicked: CSVHelper.saveListModel(libraryModel, "data.csv")
        }
        TableView {
            width: root.width
            height: 400
            TableViewColumn {
                role: "title"
                title: "Title"
                width: 100
            }
            TableViewColumn {
                role: "author"
                title: "Author"
                width: 200
            }
            model: libraryModel
        }
    }
}

Upvotes: 1

Related Questions