Qt Model View 简便类(一)

表格、列表和树型窗口部件是 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 *coords,
QWidget *parent)
: QDialog(parent)
{
coordinates = coords;


tableWidget = new QTableWidget(0, 2);
tableWidget->setHorizontalHeaderLabels(
QStringList() << tr(“X”) << tr(“Y”));


for (int row = 0; row 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 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 再做一次修改。

欢迎大家关注公众号 :Pou 光明