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

每个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);将它的指针传递给tableView,tableView将调用它接收到的指针的方法来找出两件事:

  • 应该显示多少行和列。

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

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

我们有一个表数据集,所以从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()和缓存昂贵的查找操作时,确保数据可用是很重要的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值