上一篇文章介绍了 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>
以下是一些 GtkDropDowns 的实际应用
摘要
再次强调这一点:所有这些都是全新的 API,我们很乐意听到您对哪些方面效果良好、哪些方面效果不佳以及缺少哪些方面的反馈。