TableView QML 类型

提供显示从模型中获取数据的表格视图。 更多...

导入语句import QtQuick
继承

Flickable

继承自

TreeView

属性

附加属性

信号

附加信号

方法

详细描述

TableView 具有定义要显示的数据的 model 和定义数据应如何显示的 delegate

TableView 继承自 Flickable。这意味着虽然模型可以具有任意数量的行和列,但通常只会在视口中显示表格的子部分。一旦你滑动,新的行和列就会进入视口,而旧的行和列则退出并从视口中移除。移出行和列会被重新利用来构建进入视口的行和列。因此,TableView 支持任何大小的模型而不会影响性能。

TableView 用于显示由内置 QML 类型(如 ListModelXmlListModel)创建的模型,这些类型仅在TableView的第一列填充数据。要创建具有多列的模型,请使用 TableModel 或继承自 QAbstractItemModel 的 C++ 模型。

TableView 默认不包含标题。您可以使用 Qt Quick Controls 中的 HorizontalHeaderViewVerticalHeaderView 添加标题。

注意:TableView 只加载所需填充视口的委托项目数量。无法保证加载视口外的项目,尽管TableView有时会为了优化而预加载项目。因此,宽度或高度为零的TableView可能根本不会加载任何委托项目。

示例用法

C++ 模型

以下示例展示了如何使用 C++ 创建多列模型

#include <qqml.h>
#include <QAbstractTableModel>

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
    QML_ELEMENT
    QML_ADDED_IN_VERSION(1, 1)

public:
    int rowCount(const QModelIndex & = QModelIndex()) const override
    {
        return 200;
    }

    int columnCount(const QModelIndex & = QModelIndex()) const override
    {
        return 200;
    }

    QVariant data(const QModelIndex &index, int role) const override
    {
        switch (role) {
            case Qt::DisplayRole:
                return QString("%1, %2").arg(index.column()).arg(index.row());
            default:
                break;
        }

        return QVariant();
    }

    QHash<int, QByteArray> roleNames() const override
    {
        return { {Qt::DisplayRole, "display"} };
    }
};

然后从 QML 中如何使用它

import QtQuick
import TableModel 0.1

TableView {
    anchors.fill: parent
    columnSpacing: 1
    rowSpacing: 1
    clip: true

    model: TableModel {}

    delegate: Rectangle {
        implicitWidth: 100
        implicitHeight: 50
        Text {
            text: display
        }
    }
}

QML 模型

对于原型设计和显示非常简单的数据(例如,从网络 API),可以使用 TableModel

import QtQuick
import Qt.labs.qmlmodels

TableView {
    anchors.fill: parent
    columnSpacing: 1
    rowSpacing: 1
    clip: true

    model: TableModel {
        TableModelColumn { display: "name" }
        TableModelColumn { display: "color" }

        rows: [
            {
                "name": "cat",
                "color": "black"
            },
            {
                "name": "dog",
                "color": "brown"
            },
            {
                "name": "bird",
                "color": "white"
            }
        ]
    }

    delegate: Rectangle {
        implicitWidth: 100
        implicitHeight: 50
        border.width: 1

        Text {
            text: display
            anchors.centerIn: parent
        }
    }
}

重用项目

TableView 默认通过重用委托项目来回收利用,而不是每次将新的行和列滑动到视口中时都从 delegate 中实例化。这种方法可以根据委托的复杂性带来巨大的性能提升。

当项目被滑动出去时,它会移动到 重用池,这是一个未使用的项目内部缓存。当发生这种情况时,会发出 TableView::pooled 信号来通知项目。类似地,当项目从池中移回时,会发出 TableView::reused 信号。

在项目重用时会更新从模型来的任何项目属性。这包括 indexrowcolumn,以及任何模型角色。

注意:避免在委托内存储任何状态。如果您这样做,则在收到 TableView::reused 信号时手动重置它。

如果您有计时器或动画的项目,请在收到 TableView::pooled 信号时暂停它们。这样,您可以避免为不可见的项目使用 CPU 资源。同样,如果项目中有无法重用的资源,您可以将其释放。

如果您不想重用项目或如果 delegate 不支持重用,您可以设置 reuseItems 属性为 false

注意:在项目处于池中时,项目可能仍然处于活动状态并响应连接的信号和绑定。

以下示例显示了一个动画旋转矩形的委托。当它被放入池中时,动画临时暂停

Component {
    id: tableViewDelegate
    Rectangle {
        implicitWidth: 100
        implicitHeight: 50

        TableView.onPooled: rotationAnimation.pause()
        TableView.onReused: rotationAnimation.resume()

        Rectangle {
            id: rect
            anchors.centerIn: parent
            width: 40
            height: 5
            color: "green"

            RotationAnimation {
                id: rotationAnimation
                target: rect
                duration: (Math.random() * 2000) + 200
                from: 0
                to: 359
                running: true
                loops: Animation.Infinite
            }
        }
    }
}

行高和列宽

当一个新的列被滑动到视图中时,TableView将调用columnWidthProvider来确定其宽度。如果已设置,则此函数将独立决定列的宽度。否则,它将检查是否使用了setColumnWidth()设置了明确的宽度。如果没有,将使用implicitColumnWidth()。列的隐式宽度是当前在该列中加载的代理项中找到的最大隐式宽度。直接在一个代理项上设置显式width将没有效果,并且将被忽略并覆盖。相同的逻辑也适用于行高。

等效于默认逻辑的columnWidthProvider实现可能会是:

columnWidthProvider: function(column) {
    let w = explicitColumnWidth(column)
    if (w >= 0)
        return w;
    return implicitColumnWidth(column)
}

一旦列宽度得到解决,同一列中的所有其他项目都会调整为这个宽度,包括稍后滑动到视图中该项目。

注意:当整个列被滑动出视图时,列的解决宽度将被丢弃,并且当它被再次滑动进来时将被重新计算。这意味着如果宽度依赖于implicitColumnWidth,则每次计算的值可能都不同,这取决于列进入时的哪一行(因为implicitColumnWidth()只考虑当前加载的代理项)。为了避免这种情况,您应使用columnWidthProvider,或者确保同一列中的所有代理项都具有相同的implicitWidth

如果您更改rowHeightProvidercolumnWidthProvider为视口内部的行和列返回的值,您必须调用forceLayout。这会通知TableView它需要再次使用提供者函数来重新计算和更新布局。

从Qt 5.13开始,如果您想隐藏特定列,可以从该列的columnWidthProvider返回0。同样,您可以从不返回rowHeightProvider返回的值隐藏一行。如果您返回负数,TableView将回退到根据代理项计算大小。

注意:行或列的大小应该是整数,以避免项目的亚像素对齐。

以下示例演示了如何设置一个简单的columnWidthProvider,同时还带有一个修改函数返回值的计时器。当数组被修改时,forceLayout会被调用以使更改生效

TableView {
    id: tableView

    property var columnWidths: [100, 50, 80, 150]
    columnWidthProvider: function (column) { return columnWidths[column] }

    Timer {
        running: true
        interval: 2000
        onTriggered: {
            tableView.columnWidths[2] = 150
            tableView.forceLayout();
        }
    }
}

编辑单元格

您可以通过提供编辑代理来允许用户编辑表格单元格。编辑代理将根据editTriggers来实例化,默认情况下是当用户双击单元格或按下例如Qt::Key_EnterQt::Key_Return。通过在delegate上设置TableView::editDelegate来设置编辑代理,这是一个您设置的附加属性。以下代码片段演示了如何做到这一点

    TableView {
        id: tableView
        anchors.fill: parent
        clip: true

        model: TableModel {
            TableModelColumn { display: "name" }
            rows: [ { "name": "Harry" }, { "name": "Hedwig" } ]
        }

        selectionModel: ItemSelectionModel {}

        delegate: Rectangle {
            implicitWidth: 100
            implicitHeight: 50

            Text {
                anchors.centerIn: parent
                text: display
            }

            TableView.editDelegate: TextField {
                anchors.fill: parent
                text: display
                horizontalAlignment: TextInput.AlignHCenter
                verticalAlignment: TextInput.AlignVCenter
                Component.onCompleted: selectAll()

                TableView.onCommit: {
                    display = text
                    // 'display = text' is short-hand for:
                    // let index = TableView.view.index(row, column)
                    // TableView.view.model.setData(index, text, Qt.DisplayRole)
                }
            }
        }
    }

如果用户在编辑代理激活时按下Qt::Key_EnterQt::Key_Return,TableView 将向编辑代理发送 TableView::commit 信号,以便它可以将更改后的数据写回模型。

注意: 为了使单元格可编辑,模型需要重写 QAbstractItemModel::flags(),并返回 Qt::ItemIsEditable。默认情况下,在 QAbstractItemModel 中不会启用此标志。重写示例可能如下所示:

Qt::ItemFlags QAbstractItemModelSubClass::flags(const QModelIndex &index) const override
{
    Q_UNUSED(index)
    return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

如果 TableView 代理 定义了名为 required property bool editing 的属性,则正在编辑的代理将被设置为 true。有关如何使用的示例,请参阅 editDelegate 的文档。

覆盖和叠加

从代理实例化的所有新项目都是作为具有 z1contentItem 的父项。您可以在 Tableview 中添加自己的项目,作为 Flickable 的子项。通过控制它们的 z 值,您可以使它们在表格条目之上或之下。

以下示例显示了如何添加一些文本到表格上方,当您滑动时,这些文本会一起移动。

TableView {
    id: tableView

    topMargin: header.implicitHeight

    Text {
        id: header
        text: "A table header"
    }
}

以下示例显示了如何创建一个叠加项目,该项目始终位于特定单元格之上。由于用户(例如,在它前面调整列大小时),单元格的位置会改变,因此这需要更多代码。

Rectangle {
    id: overlay
    width: 20
    height: 20
    radius: 10
    color: "blue"

    z: 10
    parent: tableView.contentItem

    Connections {
        target: tableView
        function onLayoutChanged() {
            let item = tableView.itemAtCell(5, 5)
            let insideViewport = item !== null

            overlay.visible = insideViewport
            if (insideViewport) {
                overlay.x = item.x
                overlay.y = item.y
            }
        }
    }
}

您也可以直接将叠加项目作为单元格的子项,而不是作为 contentItem。但是这样做可能会很脆弱,因为当单元格从视图中滚动出去时,它将被卸载或重新使用。

项目选择

您可以通过将 ItemSelectionModel 分配给 selectionModel 属性来为 TableView 添加选择支持。然后它将使用此模型来控制哪些委托项目应显示为选中,哪些项目应显示为当前。您可以将 selectionBehavior 设置为控制用户是否允许选择单个单元格、行或列。

要确定委托是否选中或当前,请声明以下属性

delegate: Item {
    required property bool selected
    required property bool current
    // ...
}

注意: 必须将 selectedcurrent 属性定义为 required。这将通知 TableView 它应负责更新它们的值。如果不这样做,它们将简单地被忽略。有关更多信息,请参阅Required Properties

以下代码片段显示了应用程序如何根据 selected 属性渲染不同的委托。

    TableView {
        id: tableView
        anchors.fill: parent
        clip: true

        model: TableModel {
            TableModelColumn { display: "name" }
            rows: [ { "name": "Harry" }, { "name": "Hedwig" } ]
        }

        selectionModel: ItemSelectionModel {}

        delegate: Rectangle {
            implicitWidth: 100
            implicitHeight: 30
            color: selected ? "blue" : "lightgray"

            required property bool selected

            Text { text: display }
        }
    }

如果需要根据当前项目所在的行或列的不同位置渲染委托,则 currentRowcurrentColumn 属性也可能很有用。

注意: Qt Quick Controls 提供了一个 SelectionRectangle,可以用来让用户选择单元格。

注意: 默认情况下,当用户在单元格上轻触时,单元格将成为 current,并且任何选择都将被清除。如果您不想使用这种默认的轻触行为(例如,如果您在委托内部使用自定义指针处理程序),则可以将 pointerNavigationEnabled 设置为 false

键盘导航[1]

为了支持键盘导航,您需要将ItemSelectionModel分配给selectionModel属性。然后TableView将使用此模型来操作模型的currentIndex

将自身渲染为当前是代理的责任。您可以通过向它添加一个属性required property bool current来这样做,并让外观取决于其状态。TableView将设置current属性值。您还可以通过将keyNavigationEnabled设置为false来完全禁用键盘导航(如果您想实现自己的按键处理程序)。

以下示例演示了如何使用键盘导航以及currentselected属性

ApplicationWindow {
    width: 800
    height: 600
    visible: true
    ScrollView {
        anchors.fill: parent
        TableView {
            id: tableView
            clip: true
            interactive: true
            rowSpacing: 1
            columnSpacing: 1
            model: TableModel {
                TableModelColumn { display: "checked" }
                TableModelColumn { display: "amount" }
                TableModelColumn { display: "fruitType" }
                TableModelColumn { display: "fruitName" }
                TableModelColumn { display: "fruitPrice" }

                rows: [
                    {
                        checked: false,
                        amount: 1,
                        fruitType: "Apple",
                        fruitName: "Granny Smith",
                        fruitPrice: 1.50
                    },
                    {
                        checked: true,
                        amount: 4,
                        fruitType: "Orange",
                        fruitName: "Navel",
                        fruitPrice: 2.50
                    },
                    {
                        checked: false,
                        amount: 1,
                        fruitType: "Banana",
                        fruitName: "Cavendish",
                        fruitPrice: 3.50
                    }
                ]
            }
            selectionModel: ItemSelectionModel {}
            delegate: Rectangle {
                implicitWidth: 100
                implicitHeight: 50
                required property bool selected
                required property bool current
                border.width: current ? 2 : 0
                color: selected ? "lightblue" : palette.base
                Text{
                    text: model.display
                    padding: 12
                }
            }
        }
    }
    SelectionRectangle {
        target: tableView
    }
}

复制和粘贴[2]

为TableView实现复制和粘贴操作通常也包括使用一个QUndoStack(或任何其他的撤销/重做框架)。可以使用QUndoStack来存储对模型执行的不同操作,例如添加或删除行,或从剪贴板粘贴数据,并提供一种方法来稍后撤销它们。然而,一个描述可能操作及其如何撤销的QUndoStack应根据模型和应用程序的需求来设计。因此,TableView不提供内置API处理复制和粘贴。

以下代码片段可以用作将复制和粘贴支持添加到您的模型和TableView的参考。它使用了QAbstractItemModel中现有的mimedata API,以及QClipboard。这个代码片段按原样工作,但也可扩展以使用QUndoStack

// Inside your C++ QAbstractTableModel subclass:

Q_INVOKABLE void copyToClipboard(const QModelIndexList &indexes) const
{
    QGuiApplication::clipboard()->setMimeData(mimeData(indexes));
}

Q_INVOKABLE bool pasteFromClipboard(const QModelIndex &targetIndex)
{
    const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData();
    // Consider using a QUndoCommand for the following call. It should store
    // the (mime) data for the model items that are about to be overwritten, so
    // that a later call to undo can revert it.
    return dropMimeData(mimeData, Qt::CopyAction, -1, -1, targetIndex);
}

这两个函数可以从QML使用如下

TableView {
    id: tableView
    model: tableModel
    selectionModel: ItemSelectionModel {}

    Shortcut {
       sequence: StandardKey.Copy
       onActivated: {
           let indexes = tableView.selectionModel.selectedIndexes
           tableView.model.copyToClipboard(indexes)
       }
    }

    Shortcut {
       sequence: StandardKey.Paste
       onActivated: {
           let targetIndex = tableView.selectionModel.currentIndex
           tableView.model.pasteFromClipboard(targetIndex)
       }
    }
}

另请参阅TableView::editDelegateTableView::commiteditTriggersedit()、closeEditor()、layoutChanged()、QAbstractItemModel::mimeDataQAbstractItemModel::dropMimeDataQUndoStackQUndoCommandQClipboard

属性文档

alternatingRows : bool

此属性控制行的背景颜色是否应当交替。默认值取决于风格。

注意:此属性仅作为提示,因此可能会被自定义代理忽略。建议当此提示为true时,委托在palette.basepalette.alternateBase之间交替,以便可以从外部设置颜色。例如

background: Rectangle {
    color: control.row === control.tableView.currentRow
           ? control.palette.highlight
           : (control.tableView.alternatingRows && control.row % 2 !== 0
           ? control.palette.alternateBase
           : control.palette.base)
}

animate : bool [since 6.4]

可以将该属性设置为控制如果TableView应当动画化contentItemcontentXcontentY)。它被positionViewAtCell()使用,并在使用键盘导航当前索引时。默认值是true

如果设置为false,任何正在进行的动画将立即停止。

注意: 该属性仅作为提示。在例如目标单元格未加载的情况下,TableView可能会选择在没有任何动画的情况下定位内容项。然而,如果设置为false,动画将始终关闭。

此属性自Qt 6.4版本引入。

另请参阅 positionViewAtCell()。


bottomRow : int

此属性保留当前在视图内部可见的最后一行。

另请参阅 leftColumnrightColumntopRow


columnSpacing : real

此属性保留列之间的间距。

默认值为0


columnWidthProvider : var

此属性可以保留一个函数,该函数返回模型中每一列的列宽。当TableView需要知道特定列的宽度时,会调用该函数。该函数接收一个参数column,对于该参数TableView需要知道宽度。

自Qt 5.13起,如果您想隐藏特定列,可以为该列返回0宽度。如果您返回一个负数,TableView将根据代理项目计算宽度。

注意: 当列即将加载(或进行布局)时,通常会调用columnWidthProvider两次。第一次,以了解列是否可见并且需要加载。第二次,确定所有项目加载后列的宽度。如果您需要根据代理项目的尺寸计算列宽,则需要等待第二次调用,即所有项目都加载完毕。您可以通过调用isColumnLoaded(column)来检查此情况,如果尚未完成,则简单返回-1。

另请参阅 rowHeightProviderisColumnLoaded()和行高和列宽


columns : int [只读]

此属性保留表中的列数。

注意: columns通常等于模型中的列数,但在处理所有挂起模型更改之前可能会暂时不同。

如果模型是列表,列数将等于1

此属性为只读。


contentHeight : real

此属性保留用于容纳数据模型中行数的表格高度。这通常不等于viewheight,这意味着表格的高度可能大于或小于视口高度。由于TableView无法始终知道表格的确切高度而不加载数据模型中的所有行,因此contentHeight通常是基于最初加载的表格的估计。

如果您知道表格的高度,将一个值赋给contentHeight以避免不必要的计算和TableView的更新。

另请参阅 contentWidthrowHeightProvider


contentWidth : 实数

此属性保存了模型的列数所需的表宽度。这通常与视图的 宽度 不同,这意味着表的宽度可能大于或小于视口宽度。由于 TableView 无法在没有加载所有列的情况下总是知道表的准确宽度,因此通常 contentWidth 是基于最初加载的表进行估算。

如果您知道表的宽度,则将值分配给 contentWidth,以避免不必要的计算和 TableView 的更新。

另请参阅contentHeightcolumnWidthProvider


currentColumn : 整数 [只读]

此只读属性保存包含当前项的视图中的列。如果没有当前项,则将 -1

注意:为了使 TableView 报告当前列,您需要将 ItemSelectionModel 分配给 selectionModel

另请参阅currentRowselectionModel选择项


currentRow : 整数 [只读]

此只读属性保存包含当前项的视图中的行。如果没有当前项,则将 -1

注意:为了使 TableView 报告当前行,您需要将 ItemSelectionModel 分配给 selectionModel

另请参阅currentColumnselectionModel选择项


delegate : 组件

代理提供定义视图实例化的每个单元格项的模板。模型索引作为可访问的 index 属性公开。同样适用于 rowcolumn。根据 数据模型 的类型,模型属性也可用。

代理应使用 implicitWidthimplicitHeight 指定其大小。TableView 将根据该信息布局项。显式宽度和高度设置被忽略并覆盖。

在代理内部,您可以可选地添加一个或多个以下属性。TableView 会修改这些属性值,以通知代理其状态。这可以被代理用来根据其自身状态以不同的方式渲染。

  • 必需属性 bool current - 如果委托是 当前项,则为 true
  • 必需属性 bool selected - 如果委托是 选择项,则为 true
  • 必需属性 bool editing - true 如果委托正在被 编辑。

以下示例展示了如何使用这些属性

delegate: Rectangle {
    required property bool current
    required property bool selected
    border.width: current ? 1 : 0
    color: selected ? palette.highlight : palette.base
}

注意:委托按需实例化,可能在任何时候被销毁。如果设置了 reuseItems 属性为 true 则还会被复用。因此,你应该避免在委托中存储状态信息。

另请参阅:行高和列宽项目重用,以及 必需属性


editTriggers : 枚举 [默认值: TableView.DoubleTapped | TableView.EditKeyPressed., 自6.5版本起]

该属性持有用户开始编辑单元格的不同方式。它可以是由以下值组成的组合

常量描述
TableView.NoEditTriggers- 用户不能触发单元格的编辑。当设置此值时,TableView 将不会对任何用户交互响应打开或关闭编辑委托。但应用程序可以手动调用 edit() 和 closeEditor()。
TableView.SingleTapped- 用户可以通过单次点击来编辑单元格。
TableView.DoubleTapped- 用户可以通过双击来编辑单元格。
TableView.SelectedTapped- 用户可以通过点击来编辑 已选单元格
TableView.EditKeyPressed- 用户可以通过按下一个编辑键来编辑 当前单元格。编辑键由操作系统决定,但通常是 Qt::Key_EnterQt::Key_Return
TableView.AnyKeyPressed- 用户可以通过按下任何键(不是单元格导航键)来编辑 当前单元格。按下的键也发送到 edit delegate 内部的焦点对象。

要使 TableView.SelectedTappedTableView.EditKeyPressedTableView.AnyKeyPressed 起作用,TableView 需要有分配的 selection model,因为它们依赖于一个 当前索引 被设置。要能够接收所有的按键事件,TableView 还需要有 QQuickItem::activeFocus

在编辑单元格时,用户可以按 Qt::Key_TabQt::Key_Backtab 来发送数据并移动到下一个单元格进行编辑。此行为可以通过将 QQuickItem::activeFocusOnTabTableView 上设置为 false 来禁用。

注意:为了使单元格可编辑,delegate 需要一个附加的 edit delegate,模型需要从 QAbstractItemModel::flags() 返回 Qt::ItemIsEditable(示例在下文)。如果无法在激活指定的触发器后编辑单元格,你可以尝试显式调用 edit() 作为帮助(例如从 Button/TapHandler)。这样做将打印出警告,说明为什么单元格无法编辑。

Qt::ItemFlags QAbstractItemModelSubClass::flags(const QModelIndex &index) const override
{
    Q_UNUSED(index)
    return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

该属性是在 Qt 6.5 中引入的。

另请参阅 TableView::editDelegateTableView::commit编辑单元格


keyNavigationEnabled : bool [自 6.4 开始]

此属性可以设置以控制用户是否能够使用键盘更改 当前索引。默认值是 true

注意:要使 TableView 支持键盘导航,您需要将 ItemSelectionModel 分配给 selectionModel

此属性自Qt 6.4版本引入。

另请参阅 键盘导航selectionModelselectionBehaviorpointerNavigationEnabledinteractive


leftColumn : int

此属性保留当前在视图中可见的最左侧列。

另请参阅 rightColumntopRowbottomRow


model : model

此属性保留提供表格数据的数据模型。

模型提供用于在视图中创建项的数据集。模型可以直接在 QML 中使用 TableModelListModelObjectModel 或通过自定义 C++ 模型类提供。C++ 模型必须是 QAbstractItemModel 或简单列表的子类。

另请参阅 数据模型


pointerNavigationEnabled : bool [自 6.4 开始]

此属性可以设置以控制用户是否能够使用鼠标或触摸更改 当前索引。默认值是 true

此属性自Qt 6.4版本引入。

另请参阅 selectionModelkeyNavigationEnabledinteractive


resizableColumns : bool [自 6.5 开始]

此属性保留是否允许用户通过在单元格之间拖动来调整列的大小。默认值是 false

该属性是在 Qt 6.5 中引入的。


resizableRows : bool [自 6.5 开始]

此属性保留是否允许用户通过在单元格之间拖动来调整行的大小。默认值是 false

该属性是在 Qt 6.5 中引入的。


reuseItems : bool

此属性保留是否应重用从 delegate 实例化的项。如果设置为 false,则销毁任何当前池中的项。

另请参阅 重用项TableView::pooledTableView::reused


rightColumn : int

此属性保留当前在视图中可见的最右侧列。

另请参阅 左侧列leftColumn顶部行topRow底部行bottomRow


rowHeightProvider : var

此属性可以保存一个函数,该函数返回模型中每一行的行高。每当 TableView 需要知道特定行的高度时,都会调用该函数。该函数接受一个参数,row,对于该参数,TableView 需要知道其高度。

从 Qt 5.13 开始,如果您想隐藏特定行,可以为该行返回 0 高度。如果返回负数,TableView 将基于代理项计算高度。

注意:rowHeightProvider 在行即将加载(或在布局时)通常会被调用两次。第一次是为了知道行是否可见以及是否应该被加载。第二次是在所有项目都已加载后确定行的高度。如果您需要根据代理项的大小计算行高,需要等待第二次调用,当所有项目都已加载。您可以通过调用 isRowLoaded(row) 来检查此情况,如果尚未如此,则简单地返回 -1。

另请参阅:rowHeightProvider、isRowLoaded() 和 行高和列宽


rowSpacing : real

此属性保存行之间的间距。

默认值为0


rows : int [只读]

此属性保存表中的行数。

注意:rows 通常等于模型中的行数,但在所有挂起的模型更改都已被处理之前可能会暂时不同。

此属性为只读。


selectionBehavior : enumeration [since 6.4]

此属性保存用户是否可以选中单元格、行或列。

常量描述
TableView.SelectionDisabled用户不能执行选择操作
TableView.SelectCells(默认值) 用户可以选中单个单元格
TableView.SelectRows用户只能选择行
TableView.SelectColumns用户只能选择列

此属性自Qt 6.4版本引入。

另请参阅:选择项目Selecting items、selectionMode 属性selectionMode、selectionModel 属性selectionModel 和 keyNavigationEnabled 属性keyNavigationEnabled


selectionMode : enumeration [since 6.6]

如果 selectionBehavior 设置为 TableView.SelectCells,此属性保存用户是否可以一次选择一个单元格,或选择多个单元格。如果 selectionBehavior 设置为 TableView.SelectRows,此属性保存用户是否可以一次选择一行,或选择多行。如果 selectionBehavior 设置为 TableView.SelectColumns,此属性保存用户是否可以一次选择一列,或选择多列。

以下模式可用

常量描述
TableView.SingleSelection用户可以选中单个单元格、行或列。
TableView.ContiguousSelection用户可以选择单个连续的单元格块。在拖动选择的同时按住 Shift 键可以增加或减小现有选择的范围。
TableView.ExtendedSelection(默认值)用户可以选择多个单独的单元格块。在拖动选择的同时按住 Shift 键可以增加或减小现有选择的范围。按住 Control 键同时拖动可以选择新的选择块,而不会清除当前选择。

该属性自 Qt 6.6 版本开始引入。

另请参阅 选择项目selectionBehaviorselectionModelkeyNavigationEnabled


selectionModel : ItemSelectionModel [since 6.2]

该属性可以设置来控制应显示哪些委托项作为已选中项,以及哪个项应显示为当前项。如果委托定义了 required property bool selected,则 TableView 会将其与其在 TableView 中的所选模型项的选中状态保持同步。如果委托定义了 required property bool current,则 TableView 会将其与 TableViewcurrentIndex 保持同步。

该属性自 Qt 6.2 版本开始引入。

另请参阅 选择项目SelectionRectanglekeyNavigationEnabledpointerNavigationEnabled


syncDirection : Qt::Orientations

如果对 syncView 设置生效,则此属性控制两个表之间的滑动方向同步。默认值为 Qt.Horizontal | Qt.Vertical,这意味着如果你在任一方向上滑动任一表,另一张表将以相同的量以相同的方向滑动。

此属性和 syncView 可用于在不同超调/欠调,速度,加速度/减速度或回弹动画等情况下,使两个 tableView 无缝同步。

典型用例包括让几个标题与表格一起滑动。

另请参阅 syncView


syncView : TableView

如果将此属性的 TableView 设置为另一个 TableView,则两个表格将在滑动、列宽/行高和间距方面根据 syncDirection 进行同步。

如果 syncDirection 包含 Qt.Horizontal,则当前 TableView 的列宽、列间距和水平滑动动作与 TableView 的同步视图同步。

如果 syncDirection 包含 Qt.Vertical,则当前 TableView 的行高、行间距和垂直滑动动作与 TableView 的同步视图同步。

另请参阅 syncDirection


topRow : int

该属性保留在当前视图中可见的最顶部行。

另请参阅 leftColumnrightColumn 以及 bottomRow


附加属性文档

TableView.editDelegate : 组件

此附加属性包含编辑代理。在开始编辑时进行实例化,并将其赋予所编辑的代理。它支持像 TableView 代理 一样的必需属性,包括 indexrowcolumn。根据模型公开的 角色名称,也提供了模型属性,例如 displayedit

当满足由 editTriggers 指定的操作,并且当前单元格可编辑时,开始编辑。

注意:为了使单元格可编辑,模型需要重写 QAbstractItemModel::flags() 并返回 Qt::ItemIsEditable

您还可以通过调用 edit() 和 closeEditor() 分别手动打开和关闭编辑代理。然后,将忽略 Qt::ItemIsEditable 标志。

当用户按下 Qt::Key_EnterQt::Key_Return(如果 TableView 设置了 QQuickItem::activeFocusOnTab,则还包括 Qt::Key_TabQt::Key_Backtab)时,编辑结束。在这种情况下,将发出 TableView::commit 信号,以便编辑代理可以响应并提交更改。如果由于其他原因结束编辑(例如,如果用户按下 Qt::Key_Escape),则不会发出信号。在任何情况下,最终都会发出 destruction() 信号。

在编辑代理显示时,其下方的单元格仍然可见,因此如果编辑代理是半透明的,或没有覆盖整个单元格,它会显得透明。如果不希望这样,可以有两种方法:让编辑代理的根元素是一个实心的 矩形,或者隐藏 TableView 代理 中的部分元素。这可以通过在其中定义一个属性 required property bool editing 来完成,并将其绑定到某些子元素的 visible 属性上。以下片段显示了如何实现这一点:

        delegate: Rectangle {
            implicitWidth: 100
            implicitHeight: 50

            required property bool editing

            Text {
                id: textField
                anchors.fill: parent
                anchors.margins: 5
                text: display
                visible: !editing
            }

            TableView.editDelegate: TextField {
                x: textField.x
                y: textField.y
                width: textField.width
                height: textField.height
                text: display
                TableView.onCommit: display = text
            }
        }

当编辑代理实例化时,TableView 将调用 QQuickItem::forceActiveFocus()。如果您想将活动焦点设置在编辑代理的某个子元素上,可以将编辑代理设置为 FocusScope

另请参阅 editTriggersTableView::commitedit()、closeEditor() 以及 编辑单元格


TableView.view : TableView

此附加属性包含管理代理实例的视图。它附加到每个代理实例。


信号文档

[自 6.5 layoutChanged ()

每当加载的行和列的布局可能发生变化时,都会发出此信号。特别是在调用 forceLayout() 时,以及调整行或列大小,或者行或列进入或离开视图区域时,都会发生这种情况。

此信号可用于更新覆盖图的几何形状等。

注意:相应的事件处理器是 onLayoutChanged

此信号是在 Qt 6.5 中引入的。

另请参阅:forceLayout() 和 覆盖和底图


附加信号文档

commit()

此信号由 编辑代理发出。

编辑代理活动时,并且用户按下 Qt::Key_EnterQt::Key_Return 时,会发出此附加信号。如果 TableView 设置了 QQuickItem::activeFocusOnTab,并且用户按下 Qt::Key_TabQt::Key_Backtab,同样会发出此信号。

如果由于除上述之外的原因结束编辑,将不会发出此信号。例如,如果用户按下 Qt::Key_Escape,在代理外轻触,正在编辑的行或列被删除,或应用程序调用 closeEditor()。

收到此信号后,编辑代理应将任何更改后的数据写回模型。

注意:应将此属性附加到 编辑代理,而不是附加到 代理

注意:相应的事件处理器是 onCommit

另请参阅:TableView::editDelegateeditTriggers编辑单元格


pooled()

此信号在项目被添加到重用池之后发出。您可以使用它来暂停项目内的计时器或动画,或者释放无法重用的资源。

只有当 reuseItems 属性设置为 true 时,才会发出此信号。

注意:相应的事件处理器是 onPooled

另请参阅:重用项reuseItemsreused


reused()

此信号在项目被重用后发出。此时,该项目已从池中取出并放置在内容视图中,并且已更新了模型属性,如索引、行和列。

当重用项目时,模型不提供的其他属性不会改变。您应该避免在委托内存储任何状态,但如果您确实存储了状态,请在接收到此信号时手动重置该状态。

此信号在重用项目时发出,而不仅仅是项目首次创建时。

只有当 reuseItems 属性设置为 true 时,才会发出此信号。

注意:相应的事件处理器是 onReused

另请参阅:重用项reuseItemspooled


方法文档

[since 6.4] point cellAtIndex(QModelIndex modelIndex)

返回视图中的单元格,该单元格对应于模型中的 modelIndex。这是一个方便函数,用于进行

Qt.point(columnAtIndex(modelIndex), rowAtIndex(modelIndex))

单元格只是一个简单地将行和列组合成单个类型的

注意: 其中 point.x 将映射到列,而 point.y 将映射到行。

此方法是在 Qt 6.4 中引入的。


Point cellAtPosition(point position, TableView includeSpacing)

返回表格中指定的 position 的单元格。 position 应相对于 内容项。如果没有已加载的单元格与 position 交集,则返回值将为 point(-1, -1)

如果将 includeSpacing 设置为 true,则一个单元格的边界框将考虑包含相邻边的一半 rowSpacingcolumnSpacing。默认值是 false

注意: 附加到 TableView输入处理程序 会将其自身安装到 内容项 而不是视图上。因此,处理程序报告的位置可以直接用于调用此函数,无需进行任何 映射

另请参阅 列间距行间距


Point cellAtPosition(real x, real y, TableView includeSpacing)

这是调用 cellAtPosition(Qt.point(x, y), includeSpacing) 的便捷方式。


clearColumnWidths()

清除使用 setColumnWidth() 设置的所有列宽。

注意: 如果设置了 syncView,并且与 Qt.Horizontal syncDirection 一起,则同步视图将控制列宽。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

另请参阅 setColumnWidth(),clearRowHeights(),以及 行高和列宽


clearRowHeights()

清除使用 setRowHeight() 设置的所有行高。

注意: 如果设置了 syncView,并且与 Qt.Vertical syncDirection 一起,则同步视图将控制行高。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

另请参阅 setRowHeight(),clearColumnWidths(),以及 行高和列宽


[since 6.5] closeEditor()

如果用户正在编辑单元格,调用此函数将停止编辑并销毁编辑代理实例。

此方法是在 Qt 6.5 中引入的。

另请参阅 edit(),TableView::editDelegate,以及 Editing cells


[since 6.4] int columnAtIndex(QModelIndex modelIndex)

返回视图中的列,它映射到模型中的 modelIndex

此方法是在 Qt 6.4 中引入的。

另请参阅 rowAtIndex() 和 index().


[since 6.2] real columnWidth(int column)

返回指定 的宽度。如果该列未加载(因此不可见),则返回值将是 -1

此方法是在 Qt 6.2 中引入的。

另请参阅 setColumnWidth(),columnWidthProviderimplicitColumnWidth(),isColumnLoaded(),以及 行高和列宽


[since 6.5] edit(QModelIndex modelIndex)

此函数开始对表示 modelIndex 的单元格进行编辑会话。如果用户已在编辑另一个单元格,则该会话结束。

通常您可以通过使用 editTriggers 来指定启动编辑会话的不同方式。如果这还不充分,您可以使用此函数。为了完全控制单元格编辑并使 TableView 不干涉,请将 editTriggers 设置为 TableView.NoEditTriggers

注意:选择模型 中,将更改 selectionModelcurrent indexmodelIndex

此方法是在 Qt 6.5 中引入的。

另请参阅 closeEditor(),editTriggersTableView::editDelegate,以及 编辑单元格


qreal explicitColumnWidth(int column)

返回使用 setColumnWidth 设置的 的宽度。这个宽度可能不同于列的实际宽度,如果使用了 columnWidthProvider。要获取列的实际宽度,请使用 columnWidth

等于 0 的返回值表示该列被指明要隐藏。等于 -1 的返回值表示尚未为该列设置显式宽度。

注意: 如果设置了 syncView,并且与 Qt.Horizontal syncDirection 一起,则同步视图将控制列宽。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

另请参阅 setColumnWidthcolumnWidth,以及 行高和列宽


qreal explicitRowHeight(int row)

返回使用 setRowHeight 设置的 的高度。这个高度可能不同于列的实际高度,如果使用了 rowHeightProvider。要获取行的实际高度,请使用 rowHeight

等于 0 的返回值表示该行被指明要隐藏。等于 -1 的返回值表示尚未为该行设置显式高度。

注意: 如果设置了 syncView,并且与 Qt.Vertical syncDirection 一起,则同步视图将控制行高。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

另请参阅 setRowHeightrowHeight,以及 行高和列宽


forceLayout()

模型变化的响应被分批处理,以确保每一帧只处理一次。这意味着在脚本执行期间,TableView 会延迟显示任何更改。更改属性时也是如此,例如 rowSpacingleftMargin

这种方法迫使 TableView 立即更新布局,以便任何最近的更改都能生效。

调用此函数会重新评估每行和每列的大小和位置。如果分配给 rowHeightProvidercolumnWidthProvider 的函数返回的值与之前分配的值不同时,则需要此操作。


[since 6.2] real implicitColumnWidth(int column)

返回指定 的隐式宽度。如果该列未加载(因此不可见),则返回值将为 -1

列的隐式宽度是该列中当前加载的委托项中找到的最大 implicitWidth。不会考虑由 columnWidthProvider 返回的宽度。

此方法是在 Qt 6.2 中引入的。

另请参阅 columnWidthProvidercolumnWidth()、isColumnLoaded() 以及 行高和列宽


[since 6.2] real implicitRowHeight(int row)

返回指定 的隐式高度。如果该行未加载(因此不可见),则返回值将为 -1

行的隐式高度是该行中当前加载的委托项中找到的最大 implicitHeight。不会考虑由 rowHeightProvider 返回的高度。

此方法是在 Qt 6.2 中引入的。

另请参阅 rowHeightProviderrowHeight()、isRowLoaded() 以及 行高和列宽


[since 6.4.3] QModelIndex index(int row, int column)

返回映射到视图中 QModelIndex

应该是视图中的行和列(表格行和表格列),而不是模型中的行和列。对于普通的 TableView,这相当于调用 model.index(row, column). 但对于 TableView 的子类,如 TreeView,其中数据模型封装在内部代理模型中,该模型将树结构扁平化为表格,则需要使用此函数来解决模型索引。

此方法自 Qt 6.4.3 以来引入。

另请参阅 rowAtIndex() 和 columnAtIndex()。


[since 6.2] bool isColumnLoaded(int column)

如果指定的已加载,则返回true

TableView加载了显示该列所需的项目时,便认为该列已被加载。这也通常意味着该列对用户来说是可见的,但并非总是如此。

此函数可以在需要迭代列的项目时使用,例如从columnWidthProvider中,以确保项目可用于迭代。

此方法是在 Qt 6.2 中引入的。


[自 6.2 版开始] Item isRowLoaded(Item row)

如果指定的已加载,则返回true

TableView加载了显示该行所需的项目时,便认为该行已被加载。这也通常意味着该行对用户来说是可见的,但并非总是如此。

此函数可以在需要迭代行的项目时使用,例如从rowHeightProvider中,以确保项目可用于迭代。

此方法是在 Qt 6.2 中引入的。


Item itemAtCell(point cell)

如果已加载,则在cell处返回代理项目;否则返回null

注意:通常只加载视图中的项目。一旦一个单元格从视图中滑动出来,其中的项目不是卸载就是转移到回收池中。因此,不应存储返回值。


[自 6.5 版开始] Item itemAtIndex(Item index)

返回表示index的单元格的实例化代理项目。如果项目没有被加载,则值将是null

注意:通常只加载视图中的项目。一旦一个单元格从视图中滑动出来,其中的项目不是卸载就是转移到回收池中。因此,不应存储返回值。

注意:如果模型不是QAbstractItemModel,您也可以使用itemAtCell(Qt.point(column, row))。但请注意,point.x映射到列,point.y映射到行。

此方法是在 Qt 6.5 中引入的。


[自 6.4 版开始] QModelIndex modelIndex(point cell)

这是一个方便的函数,用于执行

modelIndex(cell.y, cell.x)

单元格只是一个将行和列合并为一个类型的

注意:point.x将映射到列,point.y将映射到行。

此方法是在 Qt 6.4 中引入的。


positionViewAtCell(point cell, PositionMode mode, point offset, rect subRect)

根据mode指定将contentXcontentY定位,以便cell处于mode指定的位置。 mode是可以是以下以下选项的或组合

常量描述
TableView.AlignLeft将单元格定位在视图的左侧。
TableView.AlignHCenter将单元格定位在视图的水平中心。
TableView.AlignRight将单元格定位在视图的右侧。
TableView.AlignTop将单元格定位在视图的顶部。
TableView.AlignVCenter将单元格放置在视图的垂直中心。
TableView.AlignBottom将单元格放置在视图的底部。
TableView.AlignCenter相当于 (TableView.AlignHCenter | TableView.AlignVCenter)
TableView.Visible如果单元格的任何部分可见,则不采取任何操作。否则移动内容项,使整个单元格变得可见。
TableView.Contain如果整个单元格可见,则不采取任何操作。否则移动内容项,使整个单元格变得可见。如果单元格比视图大,则优先考虑单元格的左上部分。

如果没有指定垂直对齐方式,则忽略垂直定位。水平对齐也是如此。

可选地,您可以指定 offset 以在目标对齐的基础上移动 contentXcontentY 额外的像素数。例如,如果您想定位视图,使得单元格 [10, 10] 以 5 像素的边距位于左上角,您可以这样做

positionViewAtCell(Qt.point(10, 10), TableView.AlignLeft | TableView.AlignTop, Qt.point(-5, -5))

从 Qt 6.4 开始,您可以指定一个 subRect 以将位置定位在单元格内的一个矩形上,而不是整个单元格的边界矩形上。如果单元格,例如,比视图大,并且您想确保其中的特定部分可见,这将很有用。《子矩形需要是有效的,则应予以考虑。

注意:不建议使用 contentXcontentY 定位视图到特定的单元格。这是不可靠的,因为从表的开始删除项不会导致所有其他项重新定位。《TableView》有时也可以在近似位置上放置行和列,以优化速度。唯一的例外是如果单元格已经在视图中可见,这可以通过调用itemAtCell()在事先进行检查。

应在组件完成之后调用方法。为了在启动时定位视图,此方法应由 Component.onCompleted 调用。例如,要定位视图的末尾

Component.onCompleted: positionViewAtCell(Qt.point(columns - 1, rows - 1), TableView.AlignRight | TableView.AlignBottom)

注意:此函数的第二个参数以前是 Qt.Alignment。为了向后兼容,该枚举仍然可以使用。在 Qt 6.4 中使用 PositionMode 进行更改。

另请参阅:animate.


positionViewAtColumn(int column, PositionMode mode, real offset, rect subRect)

定位 {Flickable::}{contentX},使 column 位于 modeoffsetsubRect 指定的位置。

用于调用

positionViewAtCell(Qt.point(column, 0), mode & Qt.AlignHorizontal_Mask, offset, subRect)

[since 6.5] positionViewAtIndex(QModelIndex index, PositionMode mode, point offset, rect subRect)

定位视图,使 index 位于 modeoffsetsubRect 指定的位置。

用于调用

positionViewAtRow(rowAtIndex(index), mode & Qt.AlignVertical_Mask, offset.y, subRect)
positionViewAtColumn(columnAtIndex(index), mode & Qt.AlignVertical_Mask, offset.x, subRect)

此方法是在 Qt 6.5 中引入的。


positionViewAtRow(int row, PositionMode mode, real offset, rect subRect)

定位 {Flickable::}{contentY},使 row 位于 modeoffsetsubRect 指定的位置。

用于调用

positionViewAtCell(Qt.point(0, row), mode & Qt.AlignVertical_Mask, offset, subRect)

[自6.4版本起] int rowAtIndex(int modelIndex)

返回视图中与模型中的modelIndex相对应的行。

此方法是在 Qt 6.4 中引入的。

另请参阅columnAtIndex()和index


[自6.2版本起] real rowHeight(int row)

返回给定row的高度。如果行未加载(因此不可见),返回值将为-1

此方法是在 Qt 6.2 中引入的。

另请参阅setRowHeight()、rowHeightProviderimplicitRowHeight()、isRowLoaded()和行高和列宽


setColumnWidth(int column, real size)

将列column的显式宽度设置为size

如果您想读取使用此函数设置的值,应使用explicitColumnWidthcolumnWidth()将返回列的实际大小,如果设置了columnWidthProvider,则可能不同。

需要解析column的宽度时,它将首先尝试调用columnWidthProvider。只有当未设置提供者时,默认情况下才使用此函数设置的宽度。然而,您可以在此提供者内部调用explicitColumnWidth(),并在需要的情况下,调节值以始终保持在某个区间内。以下代码示例展示了如何做到这一点:

columnWidthProvider: function(column) {
    let w = explicitColumnWidth(column)
    if (w >= 0)
        return Math.max(100, w);
    return implicitColumnWidth(column)
}

如果size等于0,则列将被隐藏。如果size等于-1,则列将重置为使用implicitColumnWidth

注意:如果您更改了model,您设置的尺寸不会清除。要清除尺寸,您需要显式调用clearColumnWidths

注意: 如果设置了 syncView,并且与 Qt.Horizontal syncDirection 一起,则同步视图将控制列宽。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

注意:对于具有许多列的模型,在启动时使用setColumnWidth()为所有列设置宽度可能不太理想。这将消耗启动时间和内存(用于保存所有宽度)。更可扩展的方法是使用columnWidthProvider,或者依赖代理的隐式宽度。一个columnWidthProvider只在需要时调用,不会受到模型大小的约束。

另请参阅columnWidth()、explicitColumnWidth()、setRowHeight()、clearColumnWidths()和行高和列宽


setRowHeight(int row, real size)

将行row的显式高度设置为size

如果您想要读取使用此功能设置的值,应使用 explicitRowHeight 获取。 rowHeight 将返回行的实际高度,如果一个设置了 rowHeightProvider,则该值可能不同。

TableView 需要解析行的高度时,它将首先尝试调用 rowHeightProvider。只有在没有提供商设置的情况下,该函数设置的值才会被默认使用。但是,您可以从提供商内部调用 explicitRowHeight(),并在必要时对值进行调整,例如始终在某一定范围内。下面的片段展示了如何进行操作。

rowHeightProvider: function(row) {
    let h = explicitRowHeight(row)
    if (h >= 0)
        return Math.max(100, h);
    return implicitRowHeight(row)
}

如果 size 等于 0,则该行将被隐藏。如果 size 等于 -1,则该行将重置为使用 implicitRowHeight。您可以指定超出模型大小的行的行大小。

注意:如果您更改了 model,设置的值不会被清除。为了清除大小,您需要显式地调用 clearRowHeights

注意: 如果设置了 syncView,并且与 Qt.Vertical syncDirection 一起,则同步视图将控制行高。因此,在这种情况下,对该函数的任何调用将转发到同步视图。

注意:对于具有许多行的模型,在启动时使用 setRowHeight() 设置所有行的初始高度可能不是最优的。这将消耗启动时间和内存(用于存储所有高度)。一种更可缩放的方法是使用 rowHeightProvider,或者依赖于代理的隐式高度。只有在实际需要时才会调用 rowHeightProvider,且不受模型大小的影响。

参阅:rowHeightexplicitRowHeightsetColumnWidth,以及 行高度和列宽度


© 2024 Qt公司。此处包含的文档贡献版权属于其各自的所有者。此处提供的文档授权按自由软件基金会发布的 GNU自由文档许可证版本1.3 的条款使用。Qt及其相应标志是芬兰及全球其他国家的 Qt公司商标。所有其他商标均为其各自所有者的财产。