GTK+ 3.0:如何使用带有自定义模型项的Gtk.TreeStore?

10

我正在尝试使用Python开发一个GTK应用程序,但我在正确使用gtk.TreeStore方面遇到了困难。我的主要问题是:我已经解析了一些JSON数据,并且有自己的数据结构,它基本上是一个Python列表和两种对象:一种表示项目集合(集合不能嵌套),另一种表示项目(可能出现在列表中,也可能出现在集合中)。

我已经熟悉了TreeStore的基本用法,并成功地将项目正确地呈现在屏幕上。我不知道如何处理这样一个事实:treestore只能存储gobject类型(此时我不确定,因为我不太了解gobject类型系统)。C语言的文档列出了以下基本类型(除了PixBuf),可以插入并自动映射到Python数据类型:

例如,gtk_tree_store_new (3, G_TYPE_INT, G_TYPE_STRING, GDK_TYPE_PIXBUF); 将创建一个具有三列的新GtkTreeStore,类型分别为int、string和GdkPixbuf。

此外,它说你可以插入任何 GType。文档中的链接直接指向这段话:

一个数值,代表已注册类型的唯一标识符。

我的研究到此结束,谷歌搜索大多是 GTK 2.x 教程,没有关于插入除 strint 等其他数据类型的信息。
问题如下:
  • 是否可能实现新的 GType(或任何其他接口),以使插入自定义数据到 treestore 成为可能?如何实现?
    我已经尝试从 GObject 派生,但没有帮助。

  • 如何消除同时保留两个数据结构的情况?
    即我的解析结果和 Treestore 中的重复信息。

  • 如何处理混合内容?
    在我的情况下,我有不同附加信息的集合和项(在树形视图中作为具有或不具有子项的节点呈现)。

如果以上问题得到解决,我也可以摆脱处理选择时的困扰:很难将简单类型(如strint)与之前插入的项匹配。这样的属性必须是一个键,并且您仍然需要搜索已解析结果的列表,这是相当低效的。

提前感谢您!

与问题无直接关系的附加信息:


我认为编写一个自定义的TreeModel是一个可行的挑战,直到我在GTK 2教程中读到了这个信息:

然而,所有这些都是有代价的:除非剥离所有换行符,否则你很难用少于一千行的代码编写出一个有用的自定义模型。尽管编写自定义模型可能并不像听起来那么困难,但如果你需要跟踪大量数据,这样做可能会值得,因为它将带来更加合理的代码。

这个信息仍然有效吗?

我刚刚发现了http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm 这个网站。这对你有帮助吗?像许多资源一样,它适用于PyGTK 2.0。已过时。


请注意,一千行的 C 代码相当于大约两百行的 Python 代码。 - ptomato
我已经实现了一个不到100行的自定义Treemodel。我认为主要问题可能是性能,因为原始的C函数被Python函数替换了。 - nadapez
有一个相关的问题。在其评论中,有一个链接指向一个自定义实现的Python 3 Treemodel界面的示例。https://dev59.com/q4_ea4cB1Zd3GeqPKiz0 - 把友情留在无盐
1个回答

17
问题解决了!为了其他遇到同样问题的人,我将列出一些有用的资源和我的示例代码。如果您知道如何做到这一点,那么没关系,因为实际上没有文档可以参考。

针对使用 Person 填充 TreeView 并在按钮单击时打印所选 Person 的完整示例代码:

from gi.repository import Gtk
from gi.repository import GObject

class Person (GObject.GObject):
    name = GObject.property(type=str)
    age = GObject.property(type=int)
    gender = GObject.property(type=bool, default=True)

    def __init__(self):
        GObject.GObject.__init__(self)

    def __repr__(self):
        s = None
        if self.get_property("gender"): s = "m"
        else: s = "f"
        return "%s, %s, %i" % (self.get_property("name"), s, self.get_property("age"))

class MyApplication (Gtk.Window):

    def __init__(self, *args, **kwargs):
        Gtk.Window.__init__(self, *args, **kwargs)
        self.set_title("Tree Display")
        self.set_size_request(400, 400)
        self.connect("destroy", Gtk.main_quit)
        self.create_widgets()
        self.insert_rows()
        self.show_all()

    def create_widgets(self):
        self.treestore = Gtk.TreeStore(Person.__gtype__)
        self.treeview = Gtk.TreeView()
        self.treeview.set_model(self.treestore)
        column = Gtk.TreeViewColumn("Person")

        cell = Gtk.CellRendererText()
        column.pack_start(cell, True)

        column.set_cell_data_func(cell, self.get_name)

        self.treeview.append_column(column)
        vbox = Gtk.VBox()
        self.add(vbox)
        vbox.pack_start(self.treeview, True, True, 0)

        button = Gtk.Button("Retrieve element")
        button.connect("clicked", self.retrieve_element)
        vbox.pack_start(button, False, False, 5)

    def get_name(self, column, cell, model, iter, data):
        cell.set_property('text', self.treestore.get_value(iter, 0).name)

    def insert_rows(self):
        for name, age, gender in [("Tom", 19, True), ("Anna", 35, False)]:
            p = Person()
            p.name = name
            p.age = age
            p.gender = gender
            self.treestore.append(None, (p,))

    def retrieve_element(self, widget):
        model, treeiter = self.treeview.get_selection().get_selected()
        if treeiter:
            print "You selected", model[treeiter][0]

if __name__ == "__main__":
    GObject.type_register(Person)
    MyApplication()
    Gtk.main()

3
针对Python3用户:更改print语句并添加“import gi”和“gi.require_version(“Gtk”、“3.0”)”这两行代码,就可以开始使用了。 - dusty
非常感谢您的回答,它让我能够在我的树中包含可读的人类部分以及数据库ID。我知道这是一个非常古老的答案,但您能否解释一下Person中的名称/年龄/性别GObject.Property与稍后在insert_rows()中设置的对象成员变量之间的关系? - Kingsley
1
@Kingsley 是的,已经有一段时间了,我不记得所有的细节。从外表看来,可能是 GObject 的构造函数在幕后执行了一些魔法,将类体中的属性定义转换为字段。或者 GObject 提供了一个合适的 getattr 方法。很抱歉我不能深入细节。 - f4lco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接