上一篇文章介绍了在 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,我们很乐意听到您对哪些方面运行良好、哪些方面运行不佳以及缺少哪些方面的反馈。