重新实现 QAbstractTableModel 后 table 中的 TableView 无数据显示
TableView no data display in table after reimplementing QAbstractTableModel
我无法在我的 QML TableView 上显示数据。我已经定义了两个数组 - headers 和我想在 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]
// }
// }
}
}
}
Table.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 中 select 行,但看不到数据。感谢任何帮助。
您的代码有 2 个错误:
在 C++ 中 roleNames()
方法 returns a QHash<int, QByteArray>
所以在 Python 中你必须 return 一个键为整数的字典并且值必须是 bytes
或 QByteArray
但在您的情况下,该值是一个字符串。
数据方法必须提供视图所需的信息,在本例中它们是与 "sci"、"year" 和 "cont" 关联的角色值是 Qt.UserRole + 1
、Qt.UserRole + 2
和 Qt.UserRole + 3
,它们与 Qt.DisplayRole
不同,但在您的逻辑中,除 Qt.DisplayRole
之外的任何值都将 None 自相矛盾以上。
QML 提供了几种 TableView:QtQuick.Controls 1.x and 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"
}
}
}
输出:
我无法在我的 QML TableView 上显示数据。我已经定义了两个数组 - headers 和我想在 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]
// }
// }
}
}
}
Table.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 中 select 行,但看不到数据。感谢任何帮助。
您的代码有 2 个错误:
在 C++ 中
roleNames()
方法 returns aQHash<int, QByteArray>
所以在 Python 中你必须 return 一个键为整数的字典并且值必须是bytes
或QByteArray
但在您的情况下,该值是一个字符串。数据方法必须提供视图所需的信息,在本例中它们是与 "sci"、"year" 和 "cont" 关联的角色值是
Qt.UserRole + 1
、Qt.UserRole + 2
和Qt.UserRole + 3
,它们与Qt.DisplayRole
不同,但在您的逻辑中,除Qt.DisplayRole
之外的任何值都将 None 自相矛盾以上。QML 提供了几种 TableView:QtQuick.Controls 1.x and 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"
}
}
}
输出: