QML中TableView与QAbstractTableModel之间的关联探索

背景

项目中有一个比较复杂的表格需要实现,数据来自后台,数据的行或列会动态变化,表头的内容也会改变,要求表格能动态的显示这些数据。需要使用Model/View的结构,,实现前后端的分离。以往在用QML做界面时,模型部分使用的是TableModel(需要导入import Qt.labs.qmlmodels 1.0,参考https://doc.qt.io/qt-5.14/qml-qt-labs-qmlmodels-tablemodel.html),这个模型可以很方便的做与TableView的关联,当然,涉及到模型的数据操作也会在QML中进行。

然而,现在的要求是将模型部分全部移到C++上,使用QAbstractTableModel做后端的逻辑及数据处理,Qt官网上也有相关的例程https://doc.qt.io/qt-5.14/qml-qtquick-tableview.html

我用的Qt版本是Qt 5.14.2。这次会在官网的例程上做一些补充说明,便于以后更好的使用模型。如果我在文章中有地方说的不明白的或说错的,请大家留言评论,我会做补充和纠正。

QML的TabView 示例

创建C++模型TableModel

新建TableModel类,继承QAbstractTableModel。目录结构如下图所示。
在这里插入图片描述

其中基础代码如下,有修改:
tablemodel.h中的代码

#ifndef TABLEMODEL_H
#define TABLEMODEL_H

#include <QAbstractTableModel>

class TableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    TableModel();

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

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

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

        return QVariant();
    }

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

#endif // TABLEMODEL_H

tablemodel.cpp中的代码

#include "tablemodel.h"

TableModel::TableModel()
{

}

注册TableModel类型

在main.cpp中通过qmlRegisterType注册C++类型到QML中。
main.cpp中的代码

#include <QGuiApplication>
#include <QQmlApplicationEngine>

//添加头文件
#include <tablemodel.h>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    //注册C++类型至QML
    qmlRegisterType<TableModel>("TableModel", 0, 1, "TableModel");

    QQmlApplicationEngine engine;

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

创建TableView和绑定模型

在main.qml中创建TableView并绑定模型TableModel
main.qml中的代码

import QtQuick 2.14
import QtQuick.Controls 2.14

//导入C++的类
import TableModel 0.1

ApplicationWindow {
    visible: true
    width: 640
    height: 480

    TableView {
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.fill: parent
        anchors.margins: 24

        interactive: false //禁止拂动

        columnSpacing: 8
        rowSpacing: 8
        clip: true

        model: TableModel {
            id: tableModel
        }

        delegate: Rectangle {
            implicitWidth: 50
            implicitHeight: 30
            Label {
                text: display
                anchors.centerIn: parent
            }
        }
    }
}

运行效果:
在这里插入图片描述
为了能更好的进行改造,我先对上述代码几个重点进行说明一下:

1. 数据角色

在tablemodel.h的roleNames函数中,返回了QHash类型的{ {Qt::DisplayRole, “display”} }值,对应的,在main.qml->TableView->delegate中,Label的属性text也绑定了display。
这么使用的原因是,QML会根据数据角色属性去使用tablemodel.h中的data()函数查找数据。在QML中如果绑定的属性是display,那么在data()中的role参数等于display对应的值。在tablemodel.h中使用qDebug()打印数据。为了进行测试,修改了tablemodel.h的代码和main.qml的代码
tablemodel.h中的修改代码

QVariant data(const QModelIndex &index, int role) const override
    {
        qDebug() << role << index.row() << index.column();
        switch (role) {
            case Qt::DisplayRole:
                if(index.column() == 0) {
                    return QString("display");
                } else {
                    return QString("");
                }
            case Qt::UserRole:
                if(index.column() == 1) {
                    return QString("user");
                } else {
                    return QString("");
                }
            case Qt::UserRole + 1:
                if(index.column() == 2) {
                    return QString("name");
                } else {
                    return QString("");
                }
            break;
            default:
                break;
        }

        return QVariant();
    }

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

main.qml中的修改代码

delegate: Rectangle {
            implicitWidth: 50
            implicitHeight: 30

            Label {
                text: display
                anchors.centerIn: parent
            }
            Label {
                text: user
                anchors.centerIn: parent
            }
            Label {
                text: name
                anchors.centerIn: parent
            }
        }

打印的内容中,256是Qt::UserRole的值,257是Qt::UserRole + 1的值,0是Qt::DisplayRole的值。可以看到,在TableView建立后,在代理中的每一个数据角色都会循环调用一遍data()。同时data()的调用是Z字形的,先查询一行的每列,再查询下一行。我这里在处理data()时,第一列显示角色为display的值,第二列显示角色为user的值,第三列显示角色为name的值。
在这里插入图片描述
在这里插入图片描述

2. 未完待续。。。

今天先写到这里,后续将继续补充QML中TableView和C++ TableModel的联动。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 在QML,可以使用TableView元素创建表格。使用model属性来指定表格的数据来源,其的属性要使用TableModel类型。可以使用表头的visible属性和表头项来设置表格的表头。可以使用delegate属性和属性代理来设置表格单元格的样式和内容。还可以使用resizeMode属性来设置表格的列宽自适应模式。最后,将TableView元素添加到适当的布局容器来将表格放置在应用程序。 ### 回答2: QML是一种基于Qt框架的声明式语言,用于快速开发并实现用户界面。其TableView就是一种常见的控件,用于展示多行多列的数据。 TableView的用法与其他控件类似,可以在QML文件直接创建一个TableView: ``` TableView { // 设置表格的宽度和高度 width: 300 height: 200 // 设置表格的model(即数据),可以是Javascript的数组或者ListModel等数据结构 model: ListModel { ListElement { name: "Tom"; age: 20 } ListElement { name: "Lucy"; age: 18 } ListElement { name: "Kate"; age: 22 } } // 设置表格的行和列的数量、宽度 TableViewColumn { role: "name"; title: "Name"; width: 100 } TableViewColumn { role: "age"; title: "Age"; width: 100 } } ``` 上述代码,首先设置了TableView的宽度和高度,然后通过model属性设置了表格的数据。在这里,我们使用了ListModel,并将三个元素添加进去。接着,通过TableViewColumn设置了表格的列数以及每列进行展示的数据,例如第一列展示name,第二列展示age。 通过设置TableViewColumn还可以自定义每列的样式,例如: ``` TableViewColumn { role: "name" title: "Name" width: 100 delegate: Rectangle { color: "lightblue" border.color: "black" width: parent.width height: parent.height Text { text: styleData.value anchors.centerIn: parent } } } ``` 上述代码,我们添加了一个Rectangle作为每列的样式,并且使用了Text组件来实现每个单元格的内容展示。 当然,除了上述基本用法以外,TableView还支持各种事件响应、滚动条控制等功能,可根据不同的需求进一步定制。总之,QMLTableView控件在展示多行多列的数据时非常实用,方便快捷易用。 ### 回答3: QMLTableView有助于显示相对较大的表格数据。使用TableView时,您可以灵活地设置表格外观和排序规则。以下是如何使用TableView的一些示例。 首先,您需要导入QtQuick.Controls模块,以便可以使用TableView组件。 1. 基本用法 首先,在QML创建一个TableView组件。然后,将表格列数据添加到model。使用delegate设置每个单元格的外观。例如: ``` import QtQuick.Controls 1.4 TableView { TableViewColumn { role: "name" title: "Name" } TableViewColumn { role: "age" title: "Age" } model: ListModel { ListElement { name: "John" age: 30 } ListElement { name: "Mary" age: 40 } } delegate: Text { text: styleData.value } } ``` 在上面的例子,我们定义一个表格,其包含两列数据:name和age。model包含两个元素,每个元素都包含名称和年龄。最后,我们将每个单元格的值设置为Text实例的文本属性。 2. SortDelegate和SortIndicator 可以使用SortDelegate和SortIndicator组件来为表格添加排序功能。SortDelegate将包含在表格的表头。SortIndicator将指示按列排序的方向。 ``` import QtQuick.Controls 1.4 TableView { TableViewColumn { role: "name" title: "Name" sortIndicator: SortIndicator { column: 0 ascending: true } sortDelegate: Item { width: 10 Rectangle { anchors.fill: parent color: styleData.sortIndicatorColor } } } TableViewColumn { role: "age" title: "Age" sortIndicator: SortIndicator { column: 1 ascending: true } sortDelegate: Item { width: 10 Rectangle { anchors.fill: parent color: styleData.sortIndicatorColor } } } model: ListModel { ListElement { name: "John" age: 30 } ListElement { name: "Mary" age: 40 } } delegate: Text { text: styleData.value } } ``` 在上面的例子,我们为每个列设置sortDelegate和sortIndicator,以便单击表头时实现升序和降序排序。 3. 带有扩展固定行的表格 也可以为表格添加一行或多行。 在这种情况下,表格将具有固定的标题行,而剩余的部分则可以滚动。 ``` import QtQuick.Controls 1.4 TableView { TableViewColumn { role: "name" title: "Name" } TableViewColumn { role: "age" title: "Age" } TableViewColumn { role: "email" title: "Email" } model: ListModel { ListElement { name: "John" age: 30 email: "john@example.com" } ListElement { name: "Mary" age: 40 email: "mary@example.com" } ListElement { name: "David" age: 35 email: "david@example.com" } ListElement { name: "Alice" age: 25 email: "alice@example.com" } } headerDelegate: Rectangle { height: 30 color: "gray" Text { text: model ? model.roleNames()[styleData.column] : "" font.bold: true anchors.centerIn: parent } } delegate: Text { text: styleData.value } } ``` 在此示例,我们添加了一个headerDelegate,以显示在表格顶部的标题行。 headerDelegate设置了一个高度为30的矩形,其包含TableColumn的标题。要添加固定行,我们将headerDelegate属性设置为Text,以便在表格顶部显示标题。 总结: 在QML使用TableView可以轻松地显示表格数据。基本的TableView用法可以帮助您使用未排序或未分组的数据,但如果您需要更高级的功能,例如排序、固定行或多列滚动等,则可以使用SortDelegate和SortIndicator组件。最后,您还可以使用headerDelegate属性来为表格添加一个固定的标题行。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值