一、描述

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

TableView 继承了 Flickable。这意味着虽然模型可以有任意数量的行和列,但在视口内通常只能看到表格的一部分。 一旦轻弹,新的行和列就会进入视口,而旧的会退出并从视口中移除。 移出的行和列被重新用于构建移入视口的行和列。因此,TableView 支持任何大小的模型而不影响性能。

二、使用示例

2.1、C++模型

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

class testModel : public QAbstractTableModel
{
    Q_OBJECT
    QML_ELEMENT
    QML_ADDED_IN_MINOR_VERSION(1)

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

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

    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"} };
    }
};
    qmlRegisterType<testModel>("com.mycompany.qmlcomponents", 1, 0, "TestModel");
import QtQuick 2.12
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0
import QtQuick.Controls 2.5
import com.mycompany.qmlcomponents 1.0

Window
{
    width: 800
    height: 400
    visible: true

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

        model: TestModel
        {
        }

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

2.2、QML模型

import QtQuick 2.12
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0

Window
{
    width: 400;height: 400
    visible: true

    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 回收委托项,而不是在新行和新列被轻弹到视图时从委托实例化。这种方法提供了巨大的性能提升,具体取决于委托的复杂性。

当一个项目被弹出时,它会移动到重用池(未使用项目的内部缓存区)。这时会发出 pooled() 信号以通知该项目。同样,当项目从池中移回时,会发出 reused() 信号。

当项目被重用时,来自模型的任何项目属性都会更新。包括索引、行和列,还包括任何模型角色。

注意:应避免在委托中存储项目的任何状态。如果这样做,应在收到 reused() 信号时重置它。

如果项目有计时器或动画,应考虑在收到 pooled() 信号时暂停它们。这样就可以避免将 CPU 资源用于不可见的项目。同样,如果项目具有无法重用的资源,则可以将其释放。

如果不想重用项目或者如果委托不支持它,可以将重用项目 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() 函数来确定它的宽度。TableView 不存储行高或列宽,因为它旨在支持包含任意数量行和列的大型模型。

TableView 使用项中最大的隐式宽度(委托的 implicitWidth作为列宽,除非明确设置了 columnWidthProvider()。找到列宽后,同一列中的所有其他项目都将调整为该宽度,即使稍后轻弹的新项目具有更大的隐式宽度。在项目上设置显式宽度将被忽略并覆盖。

注意:列的计算宽度在从视口中弹出时会被丢弃,如果该列被弹回,则重新计算。计算始终基于该列弹入时可见的项目。这意味着该列的宽度每次都可能不同,具体取决于该列进入时所在的行。因此,应该对列中的所有项目具有相同的隐式宽度,或设置 columnWidthProvider() 。相同的逻辑适用于行高计算。

如果更改 rowHeightProvider() 或 columnWidthProvider() 为视口内的行和列返回的值,则必须调用 forceLayout()。这会通知 TableView 它需要再次使用提供程序函数来重新计算和更新布局。

如果要隐藏特定列,可以从该列的 columnWidthProvider() 返回 0。同样,可以从 rowHeightProvider() 返回 0 以隐藏行。如果返回负数,TableView 将回退以根据委托项计算大小。

        columnWidthProvider:function(column)
        {
            return 0
        }

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

五、叠加层和底层

从委托实例化的所有新项目都作为 z 值为 1 的 contentItem 的父项。可以在 Tableview 中自行添加项目作为 Flickable 的子项目。通过控制它们的 z 值,可以使它们位于表格项目的顶部或底部。

在表格顶部添加一些文本,当轻弹时,这些文本会与表格一起移动:

import QtQuick 2.12
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0

Window
{
    width: 400;height: 400
    visible: true

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

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

        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
            }
        }
    }
}

 

六、属性成员

1、bottomRow : int

      leftColumn : int

      rightColumn : int

      topRow : int

当前在视图中可见的最底部的行、最左边的列、最右边的列、最顶部的行。

2、columnSpacing : real

      rowSpacing : real

列间距、行间距。默认值为 0。

3、columnWidthProvider : var

此属性可以包含一个函数,该函数返回模型中每列的列宽。只要 TableView 需要知道特定列的宽度,就会调用它。该函数有一个参数 column 表示列数。

如果要隐藏特定列,可以为该列返回 0 宽度。如果返回负数,TableView 将根据委托项计算宽度。

      rowHeightProvider : var

类似,提供行高。

4、columns : int

      rows : int

只读属性,保存表中的列数、行数。

5、contentHeight : real

      contentWidth : real

此属性包含容纳数据模型中行数所需的表高度 / 宽度(不是 TableView 的高度 / 宽度)。如果知道表格的高度 / 宽度是多少,应为这些属性赋值,以避免对 TableView 进行不必要的计算和更新。

6、delegate : Component

委托提供了一个模板,定义了视图实例化的每个单元格项。 模型索引作为可访问的索引属性公开。 这同样适用于行和列。 根据数据模型的类型,模型的属性也可用。

委托应使用 Item::implicitHeight Item::implicitWidth 指定其大小。TableView 根据该信息布置项目。显式的宽度或高度设置将被忽略和覆盖。

注意:委托根据需要进行实例化,并且可以随时销毁。如果 reuseItems 属性设置为true,它们也会被重用。 因此,应该避免在委托中存储状态信息。

7、selectionModel : ItemSelectionModel

可以设置此属性来控制应将哪些委托项显示为选定项。

8、syncDirection : Qt::Orientations

该属性和 syncView 可以用来让两个tableView在轻弹时平滑同步。

如果设置了 syncView,则此属性控制两个表的轻弹方向的同步。默认为 Qt.Horizontal | Qt.Vertical,即如果向任一方向轻弹任一表,则另一个表也会向同一方向轻弹相同的量。

9、syncView : TableView

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

  • 如果 syncDirection 包含 Qt.Horizontal,则当前 tableView 的列宽、列间距和水平滑动移动与syncView 的同步。
  • 如果 syncDirection 包含 Qt.Vertical,则当前 tableView 的行高、行间距和垂直滑动移动与syncView 的同步。

10、reuseItems 

此属性保存是否应重用从委托实例化的项目。

七、附加属性成员

1、TableView.view : TableView

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

八、附加信号成员

1、pooled()

在将项目添加到重用池后发出此信号。可以使用它来暂停项目内正在进行的计时器或动画,或释放无法重复使用的资源。仅当 reuseItems 属性为 true 时才会发出此信号。

2、reused()

该信号在项目被重用后发出。此时,item已经从重用池中取出,放到 content view 里面,index、row、column等模型属性也都更新了。仅当 reuseItems 属性为 true 时才会发出此信号。

九、成员函数

1、Point cellAtPos(point position, bool includeSpacing)

      Point cellAtPos(real x, real y, bool includeSpacing)

返回视图中给定位置的单元格。如果没有单元格与 position 相交,则返回值为 point(-1, -1)。

如果 includeSpacing 设置为 true,则单元格的边界框将被视为包括每一侧相邻 rowSpacing columnSpacing 的一半。 默认值为false。

2、real columnWidth(int column)

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

应用程序负责通过使用 columnWidthProvider 来存储列宽。如果 TableView 没有设置 columnWidthProvider,则此函数最有用,否则可以调用 columnWidthProvider 设置的函数(即使对于当前不可见的列,它也可以工作。如果没有设置 columnWidthProvider,行高将等于它的implicitColumnWidth()。

      real rowHeight(int row)

类似,返回行高。

3、real implicitColumnWidth(int column)

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

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

      real implicitRowHeight(int row)

与上面类似。

4、bool isColumnLoaded(int column)

      bool isRowLoaded(int row)

是否加载了给定的列 / 行。

5、Item itemAtCell(point cell)

      Item itemAtCell(int column, int row)

如果加载,则返回单元格中的委托项,否则返回 null。

注意:通常只加载视图中可见的项目。一旦单元格从视图中弹出,里面的项目将被卸载或放置在回收池中。因此,永远不应存储返回值。

6、positionViewAtCell(point cell, Qt.Alignment alignment, point offset)

定位 Flickable::contentX Flickable::contentY 使参数1的单元格位于对齐指定的位置。

偏移量 offset 以将 contentX contentY 移动超出目标对齐方式的额外像素数。

想定位视图,使单元格 [10, 10] 以 5px 的边距位于左上角:

positionViewAtCell(Qt.point(10, 10), Qt.AlignLeft | Qt.AlignTop, Qt.point(-5, -5))
import QtQuick 2.12
import QtQuick.Window 2.12
import Qt.labs.qmlmodels 1.0

Window
{
    width: 400;height: 400
    visible: true

    TableView
    {
        id:view
        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
            }
        }
    }
    MouseArea
    {
        anchors.fill: parent
        onPressed:
        {
            view.positionViewAtCell(Qt.point(1, 1), Qt.AlignLeft | Qt.AlignTop, Qt.point(-5, -25))
        }
    }
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐