如何从 TableModel 向 qml TableView 添加标题
Posted
技术标签:
【中文标题】如何从 TableModel 向 qml TableView 添加标题【英文标题】:How to add headers to qml TableView from TableModel 【发布时间】:2019-08-01 20:19:42 【问题描述】:我需要向使用 Python 中定义的自定义模型的 TableView 添加标题。
我尝试用我的自定义标题覆盖 QAbstractTableModel 中的 headerData 函数。我正在遵循相同类型实现的此 C++ 示例中描述的相同系列步骤:Header to a TableView
很遗憾,标题仍然没有显示在表格的顶部。然而,该表确实包含来自覆盖 QAbstractTableModel 中的数据函数的数据。
Python:
class RouteTableModel(QAbstractTableModel):
def __init__(self, parent=None, *args):
super().__init__()
self._datatable = None
self._header =
0 : 'X',
1 : 'Y',
2 : 'Z'
def data(self, index, role=Value):
i = index.row()
j = index.column()
if role == self.Value:
return '0'.format(self._datatable[i][j]['value'])
elif role == self.Selected:
return self._datatable[i][j]['selected']
else:
return None
def headerData(self, section, orientation, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return self._header[section]
else:
return None
else:
return None
# create the application instance
app = QApplication(sys.argv)
# create a QML engine
engine = QQmlApplicationEngine()
# instantiate the TableModel class
xyztablemodel = RouteTableModel()
engine.rootContext().setContextProperty('XYZTableModel', xyztablemodel)
# load main QML file and start app engine
engine.load('view.qml')
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
QML:
import QtQuick 2.12
import QtQuick.Controls 2.12
GridLayout
id: gridfpc2
flow: GridLayout.TopToBottom
rows: 4
columns: 2
rowSpacing: 20
columnSpacing: 35
TableView
id: xyztable
Layout.rowSpan: 4
// Layout.alignment: Qt.AlignCenter
Layout.fillHeight: true
model: XYZTableModel
width: 350
delegate: CustomComp.XYZTableDelegate
implicitWidth: parent.width / 3
implicitHeight: 20
Python 或 qml 代码中不会出现错误消息。我希望标题填充在 TableView 中的列上方,但它们没有显示出来。
【问题讨论】:
您使用的是什么 TableView:QQC1 或 QQ? 我没有意识到有两种同名的类型。我假设它的 QQC1 因为我导入 QtQuick 和 QtQuick.Controls 第二。我如何确定我是否同时导入两者? 原来是它的 QQ:***.com/questions/57316457/… 我正在为 QtQuick 和 QtQuick.Controls 导入 2.12。该版本中仅存在 QtQuick 实现。 【参考方案1】:在您在问题中指出的示例中,它来自与 QML 提供的 TableView 非常不同的 QTableView。在您的情况下,您使用的是 QtQuick 的 TableView。此 TableView 没有标题,因此您必须实现它,在我的示例中,我将使用中继器。另一方面,无法从 QML 访问 headerData,因此我将使用 @Slot() 实现 C++ 的 Q_INVOKABLE,将返回函数的变量类型的结果作为参数传递:
main.py
from PySide2 import QtCore, QtGui, QtQml
class RouteTableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
super().__init__(parent)
self._header = 0: "X", 1: "Y", 2: "Z"
def columnCount(self, parent=QtCore.QModelIndex()):
return 3
def rowCount(self, parent=QtCore.QModelIndex()):
return 100
def data(self, index, role=QtCore.Qt.DisplayRole):
i = index.row()
j = index.column()
if role == QtCore.Qt.DisplayRole:
return "-".format(i, j)
@QtCore.Slot(int, QtCore.Qt.Orientation, result="QVariant")
def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
if orientation == QtCore.Qt.Horizontal:
return self._header[section]
else:
return str(section)
if __name__ == "__main__":
import os
import sys
app = QtGui.QGuiApplication(sys.argv)
engine = QtQml.QQmlApplicationEngine()
xyztablemodel = RouteTableModel()
engine.rootContext().setContextProperty("XYZTableModel", xyztablemodel)
current_dir = os.path.dirname(os.path.realpath(__file__))
filename = os.path.join(current_dir, "view.qml")
engine.load(QtCore.QUrl.fromLocalFile(filename))
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
view.qml
import QtQuick 2.12
import QtQuick.Controls 2.4
import QtQuick.Window 2.11
Window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
color: '#222222'
TableView
id: tableView
columnWidthProvider: function (column) return 100;
rowHeightProvider: function (column) return 60;
anchors.fill: parent
leftMargin: rowsHeader.implicitWidth
topMargin: columnsHeader.implicitHeight
model: XYZTableModel
width: 350
delegate: Rectangle
implicitWidth: 100
implicitHeight: 50
Text
text: display
Rectangle // mask the headers
z: 3
color: "#222222"
y: tableView.contentY
x: tableView.contentX
width: tableView.leftMargin
height: tableView.topMargin
Row
id: columnsHeader
y: tableView.contentY
z: 2
Repeater
model: tableView.columns > 0 ? tableView.columns : 1
Label
width: tableView.columnWidthProvider(modelData)
height: 35
text: XYZTableModel.headerData(modelData, Qt.Horizontal)
color: '#aaaaaa'
font.pixelSize: 15
padding: 10
verticalAlignment: Text.AlignVCenter
background: Rectangle color: "#333333"
Column
id: rowsHeader
x: tableView.contentX
z: 2
Repeater
model: tableView.rows > 0 ? tableView.rows : 1
Label
width: 40
height: tableView.rowHeightProvider(modelData)
text: XYZTableModel.headerData(modelData, Qt.Vertical)
color: '#aaaaaa'
font.pixelSize: 15
padding: 10
verticalAlignment: Text.AlignVCenter
background: Rectangle color: "#333333"
ScrollIndicator.horizontal: ScrollIndicator
ScrollIndicator.vertical: ScrollIndicator
【讨论】:
在已经实现标题的地方我可以使用另一个 TableView 吗?我能够使用您的解决方案来明确地实现它们,但是如果已经预先构建了一些东西,那么使用它可能是有意义的。看起来从 QtQuick.Controls 实现的 TableView 与我的模型实现不匹配,并且已在更新的版本中停用。 @MattBrauer 另一个 TableView 仅支持 QAbstractListModel 或从它们派生的类,多列思想基于角色。如果您查看文档,您将看到一个示例,然后您可以尝试在 python 中实现它:doc.qt.io/qt-5/qml-qtquick-controls-tableview.html @eyllanesc 是否可以根据TableView
的宽度让所有列的宽度相等,而不是将每列的宽度硬编码为100
?我将委托中的宽度定义为implicitWidth: tableView.width / tableView.model.columnCount()
的尝试仅部分有效。单击并拖动表格后,它将调整列的大小。
@roundtheworld 试试:columnWidthProvider: function (column) tableView.width / tableView.model.columnCount();
这不起作用...可能是因为我的TableiView
处于布局中...我将打开一个新问题。以上是关于如何从 TableModel 向 qml TableView 添加标题的主要内容,如果未能解决你的问题,请参考以下文章
从 C++ 向 QML 发出信号以读取 Q_PROPERTY 是同步事件吗?