You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用GTK4的ColumnView实现类TreeView的树形表格UI

GTK4 ColumnView 实现树形表格UI的最简方案

GTK4 中可通过 Gtk.TreeListModel 配合 ColumnView 实现树形结构的表格,无需拆分控件组合。核心思路是将普通列表模型包装为树形模型,再为 ColumnView 定义多列展示逻辑,以下是最简实现代码(基于 PyGObject):

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio, GObject

class TreeColumnViewWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(application=app, title="树形表格示例")
        self.set_default_size(600, 400)

        # 构造树形数据结构
        def build_tree_data():
            return [
                {
                    "name": "文档",
                    "size": "2.3 GB",
                    "type": "文件夹",
                    "children": [
                        {"name": "工作笔记.md", "size": "12 KB", "type": "Markdown 文件"},
                        {"name": "项目方案.pdf", "size": "1.2 MB", "type": "PDF 文件"},
                    ]
                },
                {
                    "name": "图片",
                    "size": "1.5 GB",
                    "type": "文件夹",
                    "children": [
                        {
                            "name": "旅行",
                            "size": "800 MB",
                            "type": "文件夹",
                            "children": [
                                {"name": "雪山.jpg", "size": "5 MB", "type": "JPEG 图片"},
                                {"name": "海滩.png", "size": "3 MB", "type": "PNG 图片"},
                            ]
                        },
                        {"name": "头像.svg", "size": "10 KB", "type": "SVG 图片"},
                    ]
                }
            ]

        # 创建基础列表存储
        base_store = Gio.ListStore.new(GObject.TYPE_PYOBJECT)
        for item in build_tree_data():
            base_store.append(item)

        # 定义子节点获取逻辑,包装为树形模型
        def fetch_children(node):
            if "children" in node and node["children"]:
                child_store = Gio.ListStore.new(GObject.TYPE_PYOBJECT)
                for child in node["children"]:
                    child_store.append(child)
                return child_store
            return None

        tree_model = Gtk.TreeListModel.new(base_store, False, True, fetch_children)

        # 创建ColumnView容器
        column_view = Gtk.ColumnView(model=tree_model)
        column_view.set_show_separators(True)

        # 名称列(带展开/折叠指示器)
        name_factory = Gtk.SignalListItemFactory()
        def setup_name_item(factory, list_item):
            box = Gtk.Box(spacing=6)
            box.set_halign(Gtk.Align.START)
            expander = Gtk.TreeExpander()
            label = Gtk.Label(halign=Gtk.Align.START)
            box.append(expander)
            box.append(label)
            list_item.set_child(box)

        def bind_name_item(factory, list_item):
            tree_item = list_item.get_item()
            if not tree_item:
                return
            box = list_item.get_child()
            expander = box.get_first_child()
            label = box.get_last_child()
            expander.set_list_item(list_item)
            data = tree_item.get_item()
            label.set_text(data["name"])

        name_factory.connect("setup", setup_name_item)
        name_factory.connect("bind", bind_name_item)
        name_column = Gtk.ColumnViewColumn(title="名称", factory=name_factory)
        name_column.set_expand(True)
        column_view.append_column(name_column)

        # 通用文本列创建函数(大小、类型列)
        def create_text_column(title, data_key):
            factory = Gtk.SignalListItemFactory()
            def setup_text_item(factory, list_item):
                label = Gtk.Label(halign=Gtk.Align.END)
                list_item.set_child(label)
            def bind_text_item(factory, list_item):
                tree_item = list_item.get_item()
                if tree_item:
                    data = tree_item.get_item()
                    list_item.get_child().set_text(data[data_key])
            factory.connect("setup", setup_text_item)
            factory.connect("bind", bind_text_item)
            return Gtk.ColumnViewColumn(title=title, factory=factory)

        column_view.append_column(create_text_column("大小", "size"))
        column_view.append_column(create_text_column("类型", "type"))

        # 滚动容器包裹ColumnView
        scrolled_win = Gtk.ScrolledWindow()
        scrolled_win.set_child(column_view)
        self.set_child(scrolled_win)

class TreeColumnViewApp(Gtk.Application):
    def __init__(self):
        super().__init__(application_id="org.example.TreeColumnViewDemo")

    def do_activate(self):
        win = TreeColumnViewWindow(self)
        win.present()

if __name__ == "__main__":
    app = TreeColumnViewApp()
    app.run(None)

核心实现要点

  • Gtk.TreeListModel:将普通列表模型转换为树形模型,通过自定义的fetch_children函数指定节点的子项获取逻辑
  • Gtk.TreeExpander:在名称列中添加展开/折叠指示器,实现树形层级的交互
  • 多列定义:通过SignalListItemFactory为不同列绑定对应的数据字段,实现表格式展示

内容的提问来源于stack exchange,提问作者Damn Vegetables

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 03:41:18