Qt Model/View教程——只读Table

点击上方蓝字可直接关注!方便下次阅读。如果对你有帮助,可以点个在看,让它可以帮助到更多老铁~

一直想学习Qt Model/View,最终还是看的官方教程,现在将官方教程重新在梳理下。

 

每个UI开发人员都应该了解Model/View编程!可见Model/ViewUI编程中的重要性!

那它为什么这么重要呢?

Table,、ListTree widgetsGUI中经常使用的组件。 这些小部件可以通过两种不同的方式访问其数据。 传统方式部件使用内部容器进行存储数据。,这种方法非常直观,但是,在许多特别的应用程序中,它会导致数据同步问题。 第二种方法是模型/视图编程,其中小部件不维护内部数据容器。 他们通过标准化接口访问外部数据,因此避免了数据重复。 乍一看,这似乎很复杂,但是一旦仔细研究,不仅容易掌握,而且模型/视图编程的许多好处也变得更加清晰。

 

整个教程的目录如下:

 

标准部件和模型/视图部件之间的区别

表单和模型之间的适配器

开发一个简单的模型/视图应用程序

预定义模型

中级主题:

Tree views

Selection

Delegates

Debugging with model test

 

一、 概述

模型/视图是一种用于将数据与处理数据集的小部件中的视图分离的技术。 标准窗口小部件并非旨在将数据与视图分离,这就是为什么Qt具有两种不同类型的窗口小部件的原因。 两种类型的小部件外观相同,但是它们与数据的交互方式不同。

 

1. 标准部件

 Table Widget是用户可以更改的数据元素的2D部件 可以通过读写表小部件提供的数据元素将表小部件集成到程序中。 此方法非常直观,在许多应用程序中很有用,但是使用标准表窗口部件显示和编辑数据库表可能会出现问题。 数据的两个副本必须协调一致:一个在小部件外部;另一个在小部件部。  开发人员必须负责同步两个数据副本 除此之外,数据的紧密耦合使编写单元测试更加困难

 

2. Model/View

Model/View使用了更加灵活的体系结构来提供解决方案。Model/View消除了标准小部件可能发生的数据一致性问题, 而且Model/View还可以让同一数据源在多个视图上进行显示变得更加方便;因为一个Model可以传递给许多Views 最重要的区别是Model/View部件不在表单内部存储数据。 实际上,Model/View直接对您的数据进行操作。 由于视图类不知道数据的结构,因此需要提供包装器以使数据符合QAbstractItemModel接口【译者注:这就是为什么要setMode View使用该接口进行读取和写入数据,实现QAbstractItemModel的类的任何实例都称为模型【译者注:什么是Model 一旦View接收到指向模型的指针,它将读取并显示其内容并成为其编辑器【译者注:setModel后,View自动读取数据并显示】。

 

二、 一个简单的Model/View应用程序

如果要开发Model/View应用程序,应该从哪里开始? 我们建议从一个简单的示例开始【译者注:我表示非常赞同!】,并逐步扩展它,这使得了解架构变得容易得多。 事实证明,在调用集成好的接口前尝试详细了解Model/View体系结构对于许多开发人员来说并不方便。 从具有演示数据的简单Model/View应用程序开始要容易得多。 试试看! 只需将以下示例中的数据替换为您自己的数据即可

以下是7个非常简单和独立的应用程序,它们展示了模型/视图编程的不同方面。 可以在examples/widgets/tutorials/modelview目录中找到源代码

 

1. 只读Table

我们从使用QTableView来显示数据的应用程序开始。之后我们将添加编辑功能。

只读table,效果如下:

我们创建MyModel的实例并使用tableView.setModel(&myModel 将其指针传递给tableView tableView将调用它收到的指针获得以下信息:

应显示多少行和多少列

每个单元格应显示什么内容

 

Model需要一些代码来对此做出响应。我们有一个表数据集,因此让我们从QAbstractTableModel开始,因为它比更通用的QAbstractItemModel更加易于使用。【译者注:以后会更加了解这两个类的

mymodel.h 代码:

#include <QAbstractTableModel>


class MyModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    MyModel(QObject *parent);
    int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE ;
    int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
};

QAbstractTableModel需要实现三种抽象方法

mymodel.cpp 代码:

#include "mymodel.h"


MyModel::MyModel(QObject *parent)
    :QAbstractTableModel(parent)
{
}


int MyModel::rowCount(const QModelIndex & /*parent*/) const
{
   return 2;
}


int MyModel::columnCount(const QModelIndex & /*parent*/) const
{
    return 3;
}


QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole)
    {
       return QString("Row%1, Column%2")
                   .arg(index.row() + 1)
                   .arg(index.column() +1);
    }
    return QVariant();
}

行数和列数由MyModel :: rowCount()MyModel :: columnCount()提供  当视图必须知道单元格的文本是什么时,它将调用方法MyModel :: data()  行和列信息由参数index指定,并且角色设置为Qt :: DisplayRole  下一节将介绍其他角色。 在我们的示例中,应显示的数据已生成。 在实际的应用程序中, MyModel会有一个名为MyData的成员,该成员充当所有读取和写入操作的目标

 

这个小例子说明了模型的被动性质。 该模型不知道何时使用它或需要哪些数据。 每次视图请求时,它仅提供数据

 

当需要更改模型数据时会发生什么? 视图如何认识到数据已更改并且需要再次读取? 该模型必须发出一个信号,该信号指示已更改了哪些单元格范围。 这将在第2.3节中演示

 

总结:

之前由于项目需要,使用过Qt的文件系统模型,当时直接用的现成的程序,那会儿就很不明白为什么一定要setModel,设置完后又会自己显示。教程看到这之后,终于明白了。所以我比较喜欢知道为什么这么做、这么做应该会有一个什么样的结果。

 

最后祝大家元旦快乐!2020,体验全力做一件事的幸福与艰辛!

欢迎关注公众号:

发布了91 篇原创文章 · 获赞 94 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/ACK_ACK/article/details/103798140
今日推荐