Qt Model View 简便类(一)
- 2019 年 10 月 5 日
- 筆記
表格、列表和树型窗口部件是 GUI 开发中经常会用到的窗口部件。传统的方式是窗口部件本身包含用于存储数据的内置容器。这种方式非常符合直观感受,然而,在许多复杂的应用中,这将导致数据的同步问题。早期Qt使用的就是上述的方式。第二种方式是模型/视图编程,窗口部件无需维护内部的数据容器。它们通过标准的接口获取外部数据,也因此避免了数据的重复。
提到模型/视图编程,就不得不说一下Smalltalk语言设计的大数据集可视化方法—模型—视图—控制器(Model-View-Controller,MVC)。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
Qt的Model /View可以理解是对MVC的变形,将MVC中的控制器替换成了稍微有些不同的抽象:委托(delegate)。Qt对每种类型的视图都提供了默认的委托,这对绝大多数应用程序而言已经足够了,所以通常我们不需要注意它。
对于Qt的Model /View我们可以简单的划分为3种使用级别:
①Model /View的简便类
②Model /View的预定义模型
③Model /View的自定义模型
简便类:如QListWidget、QTableWidget、QTreeWidget。
预定义模型:QStringListModel、QStanderItemModel、QFileSystemMode等模型以及数据库模型。
说了一大堆,也不是很理解。那么接下来我们用一个小例子来了解下Model /View简便类的使用。
运行环境:ubuntu、 Qt5.5.1
例子是C++ GUI Qt4 改成的Qt5,通过一个对话框显示用户可以编辑的(x,y)坐标。
一、构造函数
CoordinateSetter::CoordinateSetter(QList<QPointF> *coords, QWidget *parent) : QDialog(parent) { coordinates = coords; tableWidget = new QTableWidget(0, 2); tableWidget->setHorizontalHeaderLabels( QStringList() << tr("X") << tr("Y")); for (int row = 0; row < coordinates->count(); ++row) { QPointF point = coordinates->at(row); slot_addRow(); tableWidget->item(row, 0)->setText(QString::number(point.x())); tableWidget->item(row, 1)->setText(QString::number(point.y())); } . . . . . . setWindowTitle(tr("Coordinate Setter")); }
QTableWidget中每一个项都使用一个QTableWidgetItem表示,slot_addRow()每次都会添加两个QTableWidgetItem用来显示坐标x和y,tableWidget->item()->setText()则用来设置QTableWidgetItem的内容。
默认情况下,QTableWidget允许编辑。如果需要防止用户编辑,可以调用setEditTriggers(QAbstractItemView::NoEditTriggers).
二、slot_addRow()
void CoordinateSetter::slot_addRow() { int row = tableWidget->rowCount(); tableWidget->insertRow(row); QTableWidgetItem *item0 = new QTableWidgetItem; item0->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); tableWidget->setItem(row, 0, item0); QTableWidgetItem *item1 = new QTableWidgetItem; item1->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); tableWidget->setItem(row, 1, item1); tableWidget->setCurrentItem(item0); }
用户单击Add Row按钮时,就会触发这个槽函数,这种方式在构造函数中也经常使用。我们使用QTableWidget::insertRow()插入一个新行,使用QTableWidgetItem 创建两个Item,之后使用QTableWidget::setItem()将他们添加到列表中。
三、保存修改
void CoordinateSetter::done(int result) { if (result == QDialog::Accepted) { coordinates->clear(); for (int row = 0; row < tableWidget->rowCount(); ++row) { double x = tableWidget->item(row, 0)->text().toDouble(); double y = tableWidget->item(row, 1)->text().toDouble(); coordinates->append(QPointF(x, y)); } } QDialog::done(result); }
最后,用户点击Ok按钮时,则会清空传递给这个对话框的人坐标,并且根据这个QTableWidget的所有Item创建一个新的坐标集。运行结果如下:

如果将坐标存储到数据库,这样则会有更好的展示效果。以后有机会会结合之前的sqlite再做一次修改。