上一篇文章介绍了 3.98.5 版本中引入的整体列表视图框架,并展示了一些示例。在这篇文章中,我们将深入探讨一些技术领域,并研究一些相关主题。
树
GtkTreeView 的一个重要特性是它可以显示树。毕竟,这就是它的名字的由来。GtkListView 侧重于普通列表,并使处理这些列表更加容易。特别是,GListModel API 比 GtkTreeModel 简单得多——这就是为什么自定义树模型实现相对较少的原因,但 GTK 4 已经有了大量的列表模型。
但有时我们仍然需要显示树。这其中有一些复杂性,但我们已经找到了一种方法来实现它。
模型
我们需要的第一个要素是一个模型。由于 GListModel 表示项目的线性列表,我们必须更加努力地使其处理树。
GtkTreeListModel 通过添加一种方法来展开项目,按需创建新的子列表模型来实现这一点。GtkTreeListModel 中的项目是 GtkTreeListRow 的实例,它包装了模型中的实际项目,并且有一些函数(如 gtk_tree_list_row_get_children())来获取子模型的项目,以及 gtk_tree_list_row_get_item() 来获取原始项目。GtkTreeListRow 有一个 :expanded 属性,用于跟踪当前是否显示子项。
树列表模型的核心是 GtkTreeListModelCreateModelFunc,它接受列表中的一个项目,并返回一个新的列表模型,其中包含应为树中给定项目的子项的相同类型的项目。
这是一个 GSettings 对象树列表模型的示例。该函数枚举给定 GSettings 对象的子设置,并为它们返回一个新的列表模型。
static GListModel * create_settings_model (gpointer item, gpointer unused) { GSettings *settings = item; char **schemas; GListStore *result; guint i; schemas = g_settings_list_children (settings); if (schemas == NULL || schemas[0] == NULL) { g_free (schemas); return NULL; } result = g_list_store_new (G_TYPE_SETTINGS); for (i = 0; schemas[i] != NULL; i++) { GSettings *child = g_settings_get_child (settings, schemas[i]); g_list_store_append (result, child); g_object_unref (child); } g_strfreev (schemas); return G_LIST_MODEL (result); }
展开器
我们需要的下一个要素是一个显示展开器箭头的部件,用户可以单击它来控制 :expanded 属性。这由 GtkTreeExpander 部件提供。正如 GtkTreeListRow 项目包装模型中的底层项目一样,您可以使用 GtkTreeExpander 部件来包装用于显示项目的部件。
以下是树展开器在我们的 GSettings 示例中的实际效果
完整示例可以在这里找到。
排序
在我们离开树之前要谈的最后一个主题是排序。列表通常有多种排序方式:a-z、z-a、忽略大小写等等。列视图通过允许您将排序器与列关联来支持此功能,用户可以通过单击列标题来激活排序器。此 API 是
gtk_column_view_column_set_sorter (column, sorter)
在对树进行排序时,您通常希望排序顺序应用于树中给定级别的项目,而不是跨级别应用,因为那样会打乱树结构。GTK 通过 GtkTreeListRowSorter 支持此功能,它包装了现有的排序器并使其遵守树结构
sorter = gtk_column_view_get_sorter (view); tree_sorter = gtk_tree_list_row_sorter_new (sorter); sort_model = gtk_sort_list_model_new (tree_model, tree_sorter); gtk_column_view_set_model (view, sort_model);
总之,在新的列表部件中,树的重要性有所降低,它们为机制增加了很多复杂性,但它们在列表视图和列视图中都得到了完全支持
组合框
单元格渲染器使用的更麻烦的领域之一是我们的单选控件:GtkComboBox。这从来都不是一个好的选择,特别是与嵌套菜单结合使用时。因此,我们渴望在新列表视图机制上尝试 GtkComboBox 的替代品。
从设计方面来看,人们也一直希望组合框能够做得更好,正如这个 2015 年的模拟图所见
五年后,我们终于有了一个替代部件。它被称为 GtkDropDown。新部件的 API 尽可能简单,几乎所有工作都由列表模型和项目工厂机制完成。基本上,您可以使用 gtk_drop_down_new() 创建一个下拉列表,然后为其提供一个工厂和一个模型,就完成了。
由于大多数选项都由简单的字符串组成,因此有一个方便的方法可以从字符串数组中为您创建模型和工厂。
const char * const times[] = { "1 minute", "2 minutes", "5 minutes", "20 minutes", NULL }; button = drop_down_new (); gtk_drop_down_set_from_strings (GTK_DROP_DOWN (button), times);
此便捷 API 与 GtkComboBoxText 非常相似,GtkBuilder 支持也非常相似。您可以在 ui 文件中指定一个字符串列表,如下所示
<object class="GtkDropDown"> <items> <item translatable="yes">Factory</item> <item translatable="yes">Home</item> <item translatable="yes">Subway</item> </items> </object>
以下是一些正在使用的 GtkDropDown
总结
再次强调这一点:所有这些都是全新的 API,我们很乐意听到您对哪些工作正常、哪些工作不正常以及缺少哪些方面的反馈。