如何从 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,将返回函数的变量类型的结果作为参数传递:

ma​​in.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 添加标题的主要内容,如果未能解决你的问题,请参考以下文章

QML:如何获取文件baseName

从 C++ (Qt5) 向 QML 项目发送信号

从 C++ 向 QML 发出信号以读取 Q_PROPERTY 是同步事件吗?

向 QAbstractListModel 子类添加新行时,QML 视图不会更新

JTable 如何使用 TableModel设置表头

如何在运行时生成的 QML 中加载图像(jpg)