Qt示例 | 地址簿例子 Address Book Example(一)

322 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情

注:示例为Qt 5.1.1中的示例。
本文旨在剖析Qt示例的源码,总结函数使用方法以及编程思想,提高自己的编程能力。

示例运行效果:

1.gif

该示例实现了一个按名称首字母分类展示的地址簿。可以添加、修改、删除一条信息。可以将当前地址簿以文件形式保存到本地,并且可以打开本地的地址簿。

文件目录:

image.png

MainWindow是主窗口。AddressWidget为窗口中的窗口中心的显示地址信息的一个子Widget。AddDialog为点击添加后弹出的添加地址信息弹框。NewAddressTab是第一个tab页,显示一行提示信息和一个添加按钮。TableModel是管理AddressWidget中数据的模式。

具体实现:

TableModel类:

image.png

TableModel继承自QAbstractTableModel,QAbstractTableModel类提供了一个抽象模型,通过继承它来创建一个表模型。

  • QAbstractTableModel提供了一组标准的接口,它将数据表示为一个二维数组。QAbstractTableModel类不可以直接使用,必须通过子类化来使用。
  • 当子类化QAbstractTableModel时,必须实现rowCount()、columnCount()和data()方法。最好还要实现headerData()方法。
  • 要使TableModel是可编辑的,必须实现insertRows()、removeRows()、setData()、flags()。
  • insertColumns()和removeColumns()方法来添加或者删除。

TableModel类中有一个成员变量listOfPairs,QList类型,存储姓名和地址信息对。

构造函数:

image.png

这里使用了两个构造函数,一个是默认构造函数,使用TableModel自己的QList<QPair<QString, QString>>。第二个构造函数为了方便起见,用参数值初始化模型中的QList<QPair<QString, QString>>。

rowCount和columnCount函数:

image.png

rowCount()和columnCount()函数返回TableModel的行数和列数。rowCount()的值将根据添加到地址簿的联系人数量而变化。columnCount()的值固定为2,因为我们只需要“姓名(name)”和“地址(address)”这两列。

Q_UNUSED(): 这个宏可以防止编译器生成关于未使用参数的警告。

data函数:

image.png

data()函数根据参数提供的模型索引值和数据角色返回数据的Name或Address。

QVariant: 表示最常见Qt数据类型的联合。即可以充当任何数据类型。
QModelIndex: QModelIndex类是专门用于定位数据模型中的数据的。QModelIndex包含指定项在模型中的位置所需的所有信息。可以使用row()、column()和parent()来创建一个项的QModelIndex,并用创建的QModelIndex作为参数获取项的信息。模型中的顶级项是没有父索引的,所以顶级项的父索引可以设为空。
Qt::DisplayRole: 模型中的数据元素都有自己的角色,即在视图中表示数据的显示类型。Qt::DisplayRole表示以文本形式呈现的数据(QString);Qt::DecorationRole表示以图标形式呈现的数据。(QColor, QIcon或QPixmap);Qt::EditRole表示在视图中以可编辑形式呈现的数据(QString)等。

image.png

headerData函数:

image.png

这个函数的作用是:显示表的标题。这里表的标题有两个,一个是“Name”,一个是“Address”。参数为指定方向、角色和节的数据。对于水平标题,节号表示列号;对于垂直标题,节号表示行号。我们只需要像例子中这样进行重写,就可以实现“Name”和“Address”这两个标题了。

insertRows函数:

image.png

insertRows()函数要在添加新数据(setData)之前被调用,否则数据将会显示不出来。调用beginInsertRows()和endInsertRows()函数,来确保所有有关联的视图都可以接收到这些变化。函数中将数据插入到本地的数据列表中。

beginInsertRows和endInsertRows: 开始行插入操作和结束插入操作。当在子类中重新实现insertRows()时,必须在将数据插入模型的底层数据存储之前调用beginInsertRows函数,在将数据插入模型的底层数据存储之后调用endInsertRows函数。
position: 数据将要插入的位置的行号。
rows: 将要出入的数据的行数。

removeRows函数:

image.png

removeRows()函数用来删除一行数据。这里的beginRemoveRows()和endRemoveRows()和上面一样。函数中将数据在本地数据列表中删除掉。

setData函数:

image.png

setData()函数将数据逐项插入表中,注意是逐项而不是逐行插入。这意味着要填充地址簿中的一行,必须调用setData()两次,因为每一行有两列。setData()函数中通过数据项的行和列进行定位,改变项的值,并将数据替换掉本地数据列表中的这一项。发出datachchanged()信号。

datachchanged: 这里的datachchanged()信号非常重要,它用来告诉所有有关联的视图更新它们的显示。
isValid: 如果模型索引有效,则返回true;否则返回false。

flags函数:

image.png

flags()函数的作用是用来返回给定索引的项目是否可编辑的标志。但是本例中没有使用QTableView对象的编辑特性。作者意图设置Qt::ItemIsEditable标志,想允许TableModel可以被编辑,但它们在这个项目里面没有用到。

getList函数:

image.png

getList()函数返回本地的listOfPairs对象,该对象保存地址簿中的列表的信息。

未完待续...