GTK+ 3.0:如何将 Gtk.TreeStore 与自定义模型项一起使用?

Posted

技术标签:

【中文标题】GTK+ 3.0:如何将 Gtk.TreeStore 与自定义模型项一起使用?【英文标题】:GTK+ 3.0: How to use a Gtk.TreeStore with custom model items? 【发布时间】:2012-06-26 01:59:57 【问题描述】:

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

我已经熟悉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。文档中的链接直接指向本段:

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

我对该主题的研究到此结束,Google 发现大部分是 GTK 2.x 教程,除了 strint 等之外,没有任何关于插入其他数据类型的内容。 问题:

是否可以实现新的 GType(或任何其他可以在树存储中插入自定义数据的接口)以及如何实现? 我已经尝试从 GObject 派生,但没有帮助。

如何避免同时保留两个数据结构? 即我的解析结果和Treestore中的重复信息。

如何处理混合内容? 就我而言,我有具有不同附加信息的集合和项目(在树视图中镜像为有或没有子节点的节点)。

如果上述问题得到解决,我在处理选择时也摆脱了这个问题:很难匹配像strint这样的简单类型来匹配我之前插入的项目。这样的属性必须是一个键,你仍然会搜索具有解析结果的列表,这是无效的。

提前谢谢你!

与问题没有直接关系的其他信息:


我认为实现自定义TreeModel 可能是一个可行的挑战,直到我在tutorial for GTK 2 中读到此内容:

但是,所有这些都是有代价的:您不可能在不到一千行的时间内编写出有用的自定义模型,除非您去掉所有换行符。编写自定义模型并不像听起来那么困难,而且值得付出努力,尤其是因为如果您有大量数据需要跟踪,它会产生更清晰的代码。

这仍然有效吗?


我刚刚遇到http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm 这有帮助吗?与 PyGTK 2.0 一样多的资源。 已弃用。

【问题讨论】:

请注意,一千行 C 语言更像是 200 行 Python。 我已经实现了一个不到 100 行的自定义 Treemodel。我认为主要问题可能是性能,因为原来的c函数被python函数取代了。 有这个相关的问题。在其评论中,有一个指向自定义实现的 python 3 Treemodel 接口示例的链接。 ***.com/questions/32611820/… 【参考方案1】:

问题解决了!对于遇到同样问题的其他人,我将收集一些有用的资源和我的示例代码。如果你知道怎么做也没关系,但它确实没有记录。

正确派生自 GObject 的属性:http://python-gtk-3-tutorial.readthedocs.org/en/latest/objects.html

如何欺骗 TreeView 接受 CellRendererText 的自定义值,包括用于实现传递给 set_cell_data_func 的函数的有用 sn-p(需要适应 TreeView)How to make GtkListStore store object attribute in a row?

关于 TreeViews 的一般良好文档http://python-gtk-3-tutorial.readthedocs.org/en/latest/treeview.html

完整的示例代码,用于在 TreeView 中填充人员并在单击按钮时打印所选人员:

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()

【讨论】:

对于 python3 用户:更改打印语句并添加行 import gigi.require_version("Gtk","3.0") 就可以了。 很多感谢这个答案,它让我的树包含人类可读的部分以及数据库 ID,我知道这是一个非常古老的答案,购买你能解释一下Person中的姓名/年龄/性别GObject.Propertyinsert_rows()后面设置的对象成员变量之间的关系吗? @Kingsley 是的,已经有一段时间了,我不记得所有细节了。从它的外观来看,GObject 的构造函数可能在幕后做了一些魔术,将类体中的属性定义转换为字段。或者也许 GObject 提供了一个合适的getattr 方法。很抱歉我无法深入了解细节?

以上是关于GTK+ 3.0:如何将 Gtk.TreeStore 与自定义模型项一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

Gtk+ 3.0 改变状态栏字体颜色

如何将 Gtk.InfoBar 的背景颜色更改为黄色?

将其他参数传递给gtk函数

GtK+3.0 多线程应用

GTK+ 3.0 编译错误:不能包含 errno.h

pkg-config 找不到 gtk+-3.0