Qt新手入门指南 - 如何创建模型/视图(二)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

每个UI开发人员都应该了解ModelView编程本教程的目标是为大家提供一个简单易懂的介绍。

Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写所有平台无差别运行更提供了几乎所有开发过程中需要用到的工具。如今Qt已被运用于超过70个行业、数千家企业支持数百万设备及应用。

在上文中我们主要为大家介绍了Model/View(模型/视图)的一些基本概念(点击这里回顾>>)本文将继续为大家介绍如何创建一个简单的模型/视图应用。

点击获取Qt Widget组件下载(Q技术交流:166830288)

2. 一个简单的模型/视图应用

如果想开发一个模型/视图应用程序应该从哪里开始呢?我们建议从一个简单的示例开始逐步扩展它这使得理解体系结构更加容易。对于许多开发人员来说在调用IDE之前试图详细理解模型/视图体系结构是不太方便的从具有演示数据的简单模型/视图应用程序开始实际上更容易。

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

2.1 只读表格

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

(文件源:examples/widgets/tutorials/modelview/1_readonly/main.cpp)

// main.cpp
#include <QApplication>
#include <QTableView>
#include "mymodel.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTableView tableView;
MyModel myModel;
tableView.setModel(&myModel);
tableView.show();
return a.exec();
}

我们有常用的main()函数:

我们创建了一个MyModel的实例并使用tableView.setModel(&myModel);将它的指针传递给tableViewtableView将调用它接收到的指针的方法来找出两件事:

  • 应该显示多少行和列。

  • 每个单元格应该打印什么内容。

模型需要一些代码来响应这一点。

我们有一个表数据集所以从QAbstractTableModel开始因为它比通用的QAbstractItemModel更容易使用。

(文件源: examples/widgets/tutorials/modelview/1_readonly/mymodel.h)

// mymodel.h
#include <QAbstractTableModel>

class MyModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit MyModel(QObject *parent = nullptr);

int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
};

QAbstractTableModel需要实现三个抽象方法。

(文件源: examples/widgets/tutorials/modelview/1_readonly/mymodel.cpp)

// 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节中演示。

2.2 用角色扩展只读示例

除了控制视图显示的文本外模型还控制文本的外观当我们稍微改变模型时得到如下结果:

事实上除了data()方法之外没有什么需要更改来设置字体、背景颜色、对齐方式和复选框。下面是data()方法它产生如上所示的结果。不同之处在于这次我们使用参数int role根据其值返回不同的信息。

(文件源: examples/widgets/tutorials/modelview/2_formatting/mymodel.cpp)

// mymodel.cpp
QVariant MyModel::data(const QModelIndex &index, int role) const
{
int row = index.row();
int col = index.column();
// generate a log message when this method gets called
qDebug() << QString("row %1, col%2, role %3")
.arg(row).arg(col).arg(role);

switch (role) {
case Qt::DisplayRole:
if (row == 0 && col == 1) return QString("<--left");
if (row == 1 && col == 1) return QString("right-->");

return QString("Row%1, Column%2")
.arg(row + 1)
.arg(col +1);
case Qt::FontRole:
if (row == 0 && col == 0) { // change font only for cell(0,0)
QFont boldFont;
boldFont.setBold(true);
return boldFont;
}
break;
case Qt::BackgroundRole:
if (row == 1 && col == 2) // change background only for cell(1,2)
return QBrush(Qt::red);
break;
case Qt::TextAlignmentRole:
if (row == 1 && col == 1) // change text alignment only for cell(1,1)
return int(Qt::AlignRight | Qt::AlignVCenter);
break;
case Qt::CheckStateRole:
if (row == 1 && col == 0) // add a checkbox to cell(1,0)
return Qt::Checked;
break;
}
return QVariant();
}

每个格式化属性将通过对data()方法的单独调用从模型请求role参数用于让模型知道正在请求哪个属性:

参考Qt命名空间文档了解更多关于Qt::ItemDataRole enum功能的信息。

现在我们需要确定使用分离模型如何影响应用程序的性能因此跟踪视图调用data()方法的频率。为了跟踪视图调用模型的频率我们在data()方法中放入了一条调试语句该语句将记录到错误输出流。在我们的小示例中data()将被调用42次。每次将光标悬停在字段上时data()将再次被调用——每个单元格调用7次。这就是为什么在调用data()和缓存昂贵的查找操作时确保数据可用是很重要的。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6