How to binding QAbstractTableModel and QML TableView ?



  • Hi All ,

    I would like create sample qt application that can extract data from python object to QML tableview .

    So i search from google and than implement QAbstractTableModel my self .

    Unfortunately , it don't work .

    Please check source code first , bottom is my source code show what i doing .

    Program most time report Segmentation fault : 11

    In some time it can successful execute but empty result .

    If i change setContextProperty timing from before load to after load QML . Program is fire . data , role names , rowCount ..etc. All thing has been invoked , just but no result to display .

    If i don't using QML , just create QTableView is coding , everything is fire now .

    But unfortunately again , i must use QML .

    Any people can let me know what i wrong ??

    My Source code here , DummyList is my implementation of QAbstractTableModel

    import sys
    import collections
    
    from PyQt5 import Qt
    
    
    class DummyList(Qt.QAbstractTableModel):
        __DEFAULT__ = Qt.QVariant()
        def __init__(self,*args,**kwargs):
            super(DummyList,self).__init__(*args,**kwargs)
            self.__roles = {}
            self.__data = []
            self.append_data(
                [
                    ("hello_would", "HELOOWOULD",),
                    ("foobar" , "ECHO",),
                    ("zebra"  , "FOO",),
                    ("ummmm"  , "BAR",)
                ],True
            )
    
    
        def append_data(self,value,header_update=False):
    
            last_index = self.rowCount()
            self.beginInsertRows(Qt.QModelIndex(),last_index,last_index)
            value = collections.OrderedDict(value)
            self.__data.append(value)
            self.endInsertRows()
            if header_update:
                for key in value.keys():
                    if key not in self.__roles.values():
                        self.__roles[ Qt.Qt.UserRole + len(self.__roles) ] = key
    
    
        def headerData(self,section,orientation,role):
    
            if role == Qt.Qt.DisplayRole:
                column = self.__roles.get(Qt.Qt.UserRole + section,Qt.QVariant())
            else:
                column = self.__roles.get(role,Qt.QVariant())
            return column
    
    
        def columnCount(self,parent=Qt.QModelIndex()):
    
            return len(self.__data[0])
    
    
        def rowCount(self,parent=Qt.QModelIndex()):
    
            return len(self.__data)
    
    
        def roleNames(self):
            """
                Model only invoked while binding to QML view .
            """
            default_roles = super(DummyList,self).roleNames()
            default_roles.update({ key:Qt.QByteArray(value.encode()) for key,value in self.__roles.items()})
            return default_roles
    
    
        def data(self,index,role):
    
            row = index.row()
            if index.isValid():
                if role >= Qt.Qt.UserRole:
                    """
                    Only fire on binding to QML
                    """
                    column = self.__roles[role]
                elif role == Qt.Qt.DisplayRole:
                    column = self.__roles[Qt.Qt.UserRole + index.column()]
                else:
                    return DummyList.__DEFAULT__
                col_data = self.__data[row][column]
                return Qt.QVariant(col_data)
            else:
                return DummyList.__DEFAULT__
    
    
    class MyWindow(Qt.QWidget):
        def __init__(self, *args):
            Qt.QWidget.__init__(self, *args)
    
            tablemodel = DummyList(self)
            tableview = Qt.QTableView()
            tableview.setModel(tablemodel)
    
            layout = Qt.QVBoxLayout(self)
            layout.addWidget(tableview)
            self.setLayout(layout)
    
    
    def main(*args,**kwargs):
        # We instantiate a QApplication passing the arguments of the script to it:
        main_app = Qt.QApplication(list(args))
    
        """
            Load tableview in QML , it will Segmentation fault: 11
            or display empty table
        """
    
        qml_app_engine = Qt.QQmlApplicationEngine(
            main_app
        )
        qml_app_engine.rootContext().setContextProperty("tableModel",DummyList())#If set property here , raise segementation most time
        qml_app_engine.load(Qt.QUrl(sys.path[0]+"/hello_table.qml"))
        #qml_app_engine.rootContext().setContextProperty("tableModel",DummyList())#Nothing to show , but data method has been invoked
        new_root = qml_app_engine.rootObjects()[0]
    
        new_root.show()
    
    
        """
        Load with custom create widget , everything is fine
        """
        #w = MyWindow()
        #w.show()
    
        # Now we can start it.
        return_code = main_app.exec_()
        #del app.global_["qml_viewer"]
        return return_code
    
    if __name__ == "__main__":
        sys.exit(main(*sys.argv))
    

    QML Source code :

    import QtQuick 2.4
    import QtQuick.Controls 1.3
    import QtQuick.Window 2.2
    import QtQuick.Dialogs 1.2
    
    
    ApplicationWindow {
        //property var tableModel
        title: qsTr("Hello World")
        width: 640
        height: 480
        TableView {
            model: tableModel
            anchors.fill: parent
            Component.onCompleted: console.log(tableModel)
            TableViewColumn {
                width:200
                role: "hello_would"
                title: "Hello Would"
            }
            TableViewColumn {
                width:200
                role: "foobar"
                title: "Foobar"
            }
            TableViewColumn {
                width:200
                role: "zebra"
                title: "Zebra"
            }
            TableViewColumn {
                width:200
                role: "ummmm"
                title: "Ummmm"
            }
    
        }
    
    
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.