Search code examples
pythonqtqmlqt5pyside2

Is it possible to connect a QML Table view to a python QAbstractModel instance?


Given a simple QML file like


TableView {
    id: myView

    topMargin: header.implicitHeight

    Text {
        id: header
        text: "A table header"
    }

    model: myModel
}

and a slightly more verbose python file

import sys

from PySide2 import QtWidgets
from PySide2.QtQuick import QQuickView
from PySide2.QtCore import Qt
from PySide2 import QtCore

class BasicModel(QtCore.QAbstractTableModel):

    def __init__(self, data):
        super(BasicModel, self).__init__()  # TODO research why the author used super this way
        self._data = data


    def headerData(self, section, orientation, role):

        if role == Qt.DisplayRole:
            return f"Test {section}"

    def data(self, index, role):
        if role == Qt.DisplayRole:
            return self._data[index.row()][index.column()]

        elif role == Qt.ToolTipRole:
            return f"This is a tool tip for [{index.row()}][{index.column()}]"

        else:
            pass

    def rowCount(self, index):
        return len(self._data)

    def columnCount(self, index):
        return len(self._data[0])


def main(argv):
    app = QtWidgets.QApplication(argv)
    view = QQuickView()
    url = QtCore.QUrl("table.qml")
    view.setSource(url)

    data = [
        [4, 9, 2],
        [1, 0, 0],
        [3, 5, 0],
        [3, 3, 2],
        [7, 8, 9],
    ]

    myModel = BasicModel(data)

    # TODO somehow connect myModel python to QML Table view.

    view.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main(sys.argv)

Is it possible to take the BasicModel instance I created in the python file and bind it to the Table myView created from the QML file?


Solution

  • You just have to export the model to QML, for example using setContextProperty:

    import sys
    
    from PySide2.QtCore import Qt, QAbstractTableModel, QUrl
    from PySide2.QtGui import QGuiApplication
    from PySide2.QtQuick import QQuickView
    
    
    class BasicModel(QAbstractTableModel):
        def __init__(self, data):
            super(BasicModel, self).__init__()
            self._data = data
    
        def headerData(self, section, orientation, role):
    
            if role == Qt.DisplayRole:
                return f"Test {section}"
    
        def data(self, index, role):
            if role == Qt.DisplayRole:
                return self._data[index.row()][index.column()]
    
        def rowCount(self, index):
            return len(self._data)
    
        def columnCount(self, index):
            return len(self._data[0])
    
    
    def main(argv):
        app = QGuiApplication(argv)
    
        data = [
            [4, 9, 2],
            [1, 0, 0],
            [3, 5, 0],
            [3, 3, 2],
            [7, 8, 9],
        ]
    
        myModel = BasicModel(data)
    
        view = QQuickView()
        view.setResizeMode(QQuickView.SizeRootObjectToView)
        view.resize(640, 480)
    
        view.rootContext().setContextProperty("myModel", myModel)
    
        url = QUrl("table.qml")
        view.setSource(url)
        view.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main(sys.argv)
    
    import QtQuick 2.15
    
    TableView {
        id: myView
    
        model: myModel
    
        delegate: Rectangle {
            implicitWidth: 100
            implicitHeight: 50
            border.width: 1
    
            Text {
                text: display
                anchors.centerIn: parent
            }
    
        }
    
    }
    

    In this post there is a similar example using pandas.