TableView重新实现QAbstractTableModel后表中没有数据显示

Posted

技术标签:

【中文标题】TableView重新实现QAbstractTableModel后表中没有数据显示【英文标题】:TableView no data display in table after reimplementing QAbstractTableModel 【发布时间】:2019-10-06 13:09:06 【问题描述】:

我无法在我的 QML TableView 上显示数据。我已经定义了两个数组——我想在 TableView 上显示的标题和行,但到目前为止没有成功。下面是最小的可重现示例。

engine.py

import os
import sys
from PySide2 import QtCore, QtGui, QtSql, QtQml
from Table import TbModel
from PySide2.QtWidgets import QApplication
if __name__ == "__main__":
    current_dir = os.path.dirname(os.path.realpath(__file__))
    app = QApplication(sys.argv)
    QtQml.qmlRegisterType(TbModel, "TbModel", 1, 0, "TbModel")
    engine = QtQml.QQmlApplicationEngine()
    qml_path = os.path.join( "main.qml")
    engine.load(QtCore.QUrl.fromLocalFile(qml_path))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

main.qml

import QtQuick 2.13
import QtQuick.Window 2.2
import QtQuick.Controls 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls 2.13
import TbModel 1.0

ApplicationWindow 
    visible: true
    id: window
    width: Screen.width
    height: Screen.height
    Grid 

    width: 300
    height: 100
    visible: true
    spacing: 200
    TableView
    
        id: idtable
        model: TbModel  
    TableViewColumn 
        role: "sci" 
        title: "sci"
    
    TableViewColumn 
        role: "year"
        title: "year"
    
    TableViewColumn 
        role: "cont"
        title: "cont"
    

        // Component.onCompleted: 

        //     var roles = model.roleNameArray()
        //                 for (var i = 0; i < model.columnCount(); i++)
        //     
        //         var column = addColumn( Qt.createQmlObject(
        //             "import QtQuick.Controls 1.1; TableViewColumn ",
        //             this) )
        //         column.role=roles[i]
        //         column.title=roles[i]

        //     
        // 
    



表格.py

from PySide2.QtCore import QAbstractTableModel, QModelIndex, QObject, Qt
from PySide2 import QtCore

class TbModel(QAbstractTableModel):
    def __init__(self, parent: QObject = None) -> None:
        super().__init__(parent)
        self.headers = ["sci", "year", "cont"]
        self.rows =    [("Newton", "1643-01-04", "Classical mechanics"),
           ("Einstein", "1879-03-14", "Relativity"),
           ("Darwin", "1809-02-12", "Evolution")]

    def rowCount(self, parent=QModelIndex()):
        return len(self.rows)

    def columnCount(self, parent=QModelIndex()):
        return len(self.headers)

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

    def headerData(self, section, orientation, role) :
        if role != Qt.DisplayRole:
            return None

        if section < 0 or section >= len(self.headers):
            return None

        return self.headers[section]

    def roleNames(self):
        roles = 
            Qt.UserRole + 1 : 'sci',
            Qt.UserRole + 2 : 'year',
            Qt.UserRole + 3 : 'cont'
        
        return roles


    @QtCore.Slot(result="QVariantList")
    def roleNameArray(self):
        names = []
        names=self.headers

        return names

我可以在 TableView 中选择行,但看不到数据。任何帮助表示赞赏。

【问题讨论】:

我只看C++ example。您没有尝试实现QHash&lt;int, QByteArray&gt; roleNames() const override 及其示例中描述的用法吗?当然,以某种 python 方式。我的意思是用Text text: display 替换代表?另外我会尝试将角色名称替换为一些符号而不是数字。 我认为你是对的,我通过实现 roleNames() 和手动插入 TableColumns 来编辑代码,但表格仍然是空的。 我猜你也必须更新data()。我的意思是应该为每个角色返回适当的值。现在您忽略除 Qt.DisplayRole 之外的所有角色,但有时您声明角色 >= Qt.UserRole + 1。headerData() 也是如此。 我实施了您的解决方案,它在一定程度上有所帮助。我将数据写入表,但只有第一行的数据 NewtonEinsteinDarwin 写入所有 3 列。我试图自己弄清楚这一点,这就是反馈延迟的原因。已实施解决方案的代码已被编辑。 @user2727167 1) 如果解决方案不正确,那么您需要立即获得反馈,因为该解决方案不仅适用于您,而且适用于整个社区。 2)如果您有解决方案,请不要将其放在您的问题中,而是要创建一个答案。请使用@username。所以我做了一个回滚,另一方面你的版本清楚地实现了我的解决方案,你的解决方案和我的有什么区别?阅读How to Ask、How to Answer 并查看tour 【参考方案1】:

您的代码有 2 个错误:

在 C++ 中,roleNames() 方法返回 QHash&lt;int, QByteArray&gt;,因此在 Python 中,您必须返回其键是整数且值必须是 bytesQByteArray 的字典,但在您的情况下,值是字符串。

数据方法必须提供视图所需的信息,在这种情况下,它们是与“sci”、“year”和“cont”关联的角色,其值为Qt.UserRole + 1Qt.UserRole + 2Qt.UserRole + 3Qt.DisplayRole 不同,但在您的逻辑中,除 Qt.DisplayRole 之外的任何值都将为 None 与上述内容相矛盾。

QML 提供了几个 TableView:QtQuick.Controls 1.x 和 QtQuick。在您的情况下,您使用的第一个模型不需要 QAbstractTableModel 而只需要一个 QAbstractListModel,因为视图使用的 QModelIndex 的列值始终为 1。

考虑到上述情况,您可能会遇到问题,因为 QML 提供了多个属于不同包的同名项目,为了解决这个问题,使用了命名空间。

综合以上情况,解决办法是:

from PySide2.QtCore import QAbstractListModel, QModelIndex, QObject, Qt, Slot


class TbModel(QAbstractListModel):
    def __init__(self, parent: QObject = None) -> None:
        super().__init__(parent)
        self.headers = ["sci", "year", "cont"]
        self.rows = [
            ("Newton", "1643-01-04", "Classical mechanics"),
            ("Einstein", "1879-03-14", "Relativity"),
            ("Darwin", "1809-02-12", "Evolution"),
        ]

    def rowCount(self, parent=QModelIndex()):
        return len(self.rows)

    def data(self, index, role=Qt.DisplayRole):
        row = index.row()
        if 0 <= row < self.rowCount():
            if role in self.roleNames():
                name_role = self.roleNames()[role].decode()
                col = self.headers.index(name_role)
                return self.rows[row][col]

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole and 0 <= section < len(self.headers):
            return self.headers[section]

    def roleNames(self):
        roles = 
        for i, header in enumerate(self.headers):
            roles[Qt.UserRole + i + 1] = header.encode()
        return roles

    @Slot(result="QVariantList")
    def roleNameArray(self):
        return self.headers
import QtQuick 2.13
import QtQuick.Window 2.13
import QtQuick.Controls 1.4 as QQC1

import TbModel 1.0

QQC1.ApplicationWindow 
    id: window
    visible: true
    width: Screen.width
    height: Screen.height

    QQC1.TableView
    
        id: idtable
        width: 600
        height: 300
        model: TbModel 
        QQC1.TableViewColumn 
            role: "sci" 
            title: "sci"
        
        QQC1.TableViewColumn 
            role: "year"
            title: "year"
        
        QQC1.TableViewColumn 
            role: "cont"
            title: "cont"
        
    

输出:

【讨论】:

以上是关于TableView重新实现QAbstractTableModel后表中没有数据显示的主要内容,如果未能解决你的问题,请参考以下文章

使用 Xib 在 Tableview Header 中快速重新加载 CollectionView

重新启动应用程序后tableview不显示tableview中的所有数据

如何在 swift 中使用 fetchedresultscontroller 重新排序 tableview 行?

使用新的 iOS 11 API 重新排序 tableview 时动画不正确

如何在swift 4中重新排序单元格后保存tableView顺序

重新加载 tableView 部分而不重新加载标题部分 - Swift