文章目录
- Qt 模型视图(三):视图类`QAbstractItemView`
- 1.基本概念
- 1.1.使用现有视图
- 1.2.使用模型
- 1.3.使用模型的多个视图
- 1.4.在视图之间共享选择
Qt 模型视图(三):视图类QAbstractItemView
模型/视图结构是一种将数据存储和界面展示分离的编程方法。模型存储数据,视图组件显示模型中的数据,在视图组件里修改的数据会被自动保存到模型里。模型的数据来源可以是内存中的字符串列表或二维表格型数据,也可以是数据库中的数据表,一种模型可以用不同的视图组件来显示数据,所以模型/视图结构是一种高效、灵活的编程结构。
1.基本概念
在模型/视图架构中,视图从模型中获取数据项并将其呈现给用户。数据的呈现方式不需要类似于模型提供的数据表示,并且可能与用于存储数据项的底层数据结构完全不同。
内容和表示的分离是通过使用QAbstractItemModel
提供的标准模型接口、QAbstractItem view
提供的标准视图接口以及使用以通用方式表示数据项的模型索引来实现的。视图通常管理从模型中获得的数据的总体布局。他们可以自己渲染单个数据项,也可以使用委托来处理渲染和编辑功能。
除了显示数据外,视图还处理项目之间的导航以及项目选择的某些方面。这些视图还实现了基本的用户界面功能,如上下文菜单和拖放。视图可以为项目提供默认编辑功能,也可以与代理一起提供自定义编辑器。
可以在没有模型的情况下构建视图,但必须提供模型才能显示有用信息。视图通过使用选项来跟踪用户选择的项目,这些选项可以为每个视图单独维护,也可以在多个视图之间共享。
某些视图(如QTableView和QTreeView
)显示标题和项目。这些也由视图类QHeaderView
实现。标头通常访问与包含它们的视图相同的模型。它们使用QAbstractItemModel::headerData()
函数从模型中检索数据,通常以标签的形式显示标题信息。可以从QHeaderView
类中子类化新标题,为视图提供更专业的标签。
1.1.使用现有视图
Qt提供了三个即用型视图类,以大多数用户熟悉的方式呈现模型中的数据。列表视图QListView
可以将模型中的项目显示为简单的列表,也可以以经典图标视图的形式显示。树状视图QTreeView
将模型中的项目显示为列表层次结构,允许以紧凑的方式表示深度嵌套的结构。表格视图QTableView
以表格的形式显示模型中的项目,非常类似于电子表格应用程序的布局。
上面显示的标准视图的默认行为应该足以用于大多数应用程序。它们提供基本的编辑功能,可以定制以满足更专业的用户界面的需求。
1.2.使用模型
我们将创建的字符串列表模型作为示例模型,使用一些数据对其进行设置,并构建一个视图来显示模型的内容。所有这些都可以在一个函数中执行:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// Unindented for quoting purposes:
QStringList numbers;
numbers << "One" << "Two" << "Three" << "Four" << "Five";
QAbstractItemModel *model = new StringListModel(numbers);
请注意,StringListModel
被声明为QAbstractItemModel
。这允许我们使用模型的抽象接口,并且即使我们用不同的模型替换字符串列表模型确保代码仍然有效。
QListView
提供的列表视图足以显示在字符串列表模型中的项目。我们构建视图,并使用以下代码行设置模型:
QListView *view = new QListView;
view->setModel(model);
视图以正常方式显示:
view->show();
return app.exec();
}
视图呈现模型的内容,通过模型的接口访问数据。当用户尝试编辑项目时,视图使用默认委托提供编辑器小部件。
上图显示了列表视图QListView
如何表示字符串列表模型中的数据。由于模型是可编辑的,因此视图会自动允许使用默认委托编辑列表中的每个项目。
1.3.使用模型的多个视图
为同一模型提供多个视图,只需为每个视图设置相同的模型即可。在下面的代码中,我们创建了两个表视图,每个视图都使用我们为本例创建的相同简单表模型:
QTableView *firstTableView = new QTableView;
QTableView *secondTableView = new QTableView;
firstTableView->setModel(model);
secondTableView->setModel(model);
在模型/视图架构中使用信号和插槽意味着对模型的更改可以传播到所有附加的视图,确保无论使用何种视图,我们都可以始终访问相同的数据。
上图显示了同一模型的两个不同视图,每个视图都包含多个选定项目。尽管模型中的数据在视图中显示一致,但每个视图都维护自己的内部选择模型。这在某些情况下可能很有用,但对于许多应用程序来说,共享选择模型是可取的。
处理项目选择
QItemSelectionModel
类提供了处理视图中项目选择的机制。默认情况下,所有标准视图都会构建自己的选择模型,并以正常方式与它们交互。视图使用的选择模型可以通过selectionModel()
函数获得,替换选择模型可以用setSelectionModel()
指定。当我们希望为同一模型数据提供多个一致的视图时,控制视图所使用的选择模型的能力非常有用。
通常,除非对模型或视图进行子类化,否则不需要直接操纵选择的内容。但是,如果需要,可以访问选择模型的接口,这在“处理项目视图中的选择”中进行了探讨。
1.4.在视图之间共享选择
虽然默认情况下视图类提供自己的选择模型很方便,但当我们在同一个模型上使用多个视图时,通常希望模型的数据和用户的选择在所有视图中都一致显示。由于视图类允许替换其内部选择模型,我们可以使用以下行在视图之间实现统一选择:
secondTableView->setSelectionModel(firstTableView->selectionModel());
第二个视图给出了第一个视图的选择模型。现在,这两个视图都在相同的选择模型上运行,使数据和所选项目保持同步。
在上面显示的示例中,使用了两个相同类型的视图来显示同一模型的数据。然而,如果使用两种不同类型的视图,则所选项目在每个视图中的表示可能会非常不同;例如,表视图中的连续选择可以表示为树视图中突出显示的项目的片段集。