GTK+ 3.0: Как использовать Gtk.TreeStore с пользовательскими элементами модели?

Я пытаюсь разработать приложение GTK на Python, и я действительно застрял с правильным использованием gtk.TreeStore. Моя основная проблема: я уже проанализировал некоторые JSON, и у меня есть собственная структура данных, которая в основном представляет собой список Python и два типа объектов: один представляет собой набор элементов (коллекции не могут быть вложенными) и один для представления элементов ( которые могут отображаться как в списке, так и в коллекции).

Я уже знаком с базовым использованием TreeStore и мне удалось правильно отобразить элементы на экране. Я не знаю, как быть с тем фактом, что хранилище дерева способно хранить только типы объектов (на данный момент я не уверен, потому что я мало знаю о системе типов объектов). В документации для 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 и ничего о вставке других типов данных, кроме str и int и т. д.
Вопросы:

  • Можно ли реализовать новый GType (или любой другой интерфейс, который сделает возможной вставку пользовательских данных в хранилище дерева) и как это сделать?
    Я уже пытался получить производные от GObject, но это не помогло.

  • Как я могу избавиться от одновременного хранения двух структур данных?
    А именно, результат синтаксического анализа и дублирующаяся информация в Treestore.

  • Как быть со смешанным содержимым?
    В моем случае у меня есть коллекции и элементы с различной дополнительной информацией (которые отображаются в древовидной структуре как узлы с дочерними элементами или без них).

Если вышеуказанные вопросы решены, я также избавляюсь от проблемы при обработке выборки: трудно сопоставить простой тип, такой как str или int, с элементом, который я вставил ранее. Такой атрибут должен быть ключом, и все равно вам придется искать список с проанализированными результатами, что совершенно неэффективно.

Заранее спасибо!

Дополнительная информация, не имеющая прямого отношения к вопросу:


Я думал, что реализация пользовательского TreeModel может быть реальной задачей, пока не прочитал это в руководство по GTK 2:

Однако за все это приходится платить: вряд ли вы напишете полезную пользовательскую модель менее чем в тысяче строк, если только не удалите все символы новой строки. Написание пользовательской модели не так сложно, как может показаться, и это может стоить затраченных усилий, не в последнюю очередь потому, что это приведет к гораздо более разумному коду, если у вас есть много данных для отслеживания.

Это все еще в силе?


Я только что наткнулся на http://www.pygtk.org/articles/subclassing-gobject/sub-classing-gobject-in-python.htm Может ли это быть полезным? Как и многие ресурсы, это для PyGTK 2.0. устарело.


person f4lco    schedule 24.06.2012    source источник
comment
Обратите внимание, что тысяча строк C больше похожа на 200 строк Python.   -  person ptomato    schedule 25.06.2012
comment
Я реализовал пользовательскую модель дерева с менее чем 100 строками. Я думаю, что основной проблемой может быть производительность, потому что оригинальные функции c заменены функциями python.   -  person nadapez    schedule 03.05.2021


Ответы (1)


Проблема решена! Для других людей, столкнувшихся с той же проблемой, я соберу несколько полезных ресурсов и мой пример кода. Ничего страшного, если вы знаете, как это сделать, но на самом деле это нигде не задокументировано.

Полный пример кода для заполнения 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()
person f4lco    schedule 24.06.2012
comment
Для пользователей python3: измените оператор печати и добавьте строки import gi и gi.require_version("Gtk","3.0"), и все готово. - person dusty; 24.10.2016