Подтвердить что ты не робот

Сериализовать Gtk TreeStore/ListStore с помощью JSON

Я сделал новый пример, который показывает намного лучше того, что я пытаюсь сделать. Новый пример дает следующий вывод. Есть ли способ, чтобы данные могли попасть в соответствующий ключ хранилища (скобки {})?

{
    "copy": [
        [
            [
                5.0,
                8.0,
                9.0
            ]
        ],
        [
            [
                4.0,
                0.0,
                1.0
            ]
        ]
    ],
    "name": "dataset1",
    "sets": [
        {
            "store": {},
            "type": "vector"
        },
        {
            "store": {},
            "type": "vector"
        }
    ]
}

Новый пример

from gi.repository import Gtk
import json
import random

class Vector(object):

    def __init__(self, data):
        self.store = Gtk.ListStore(float, float, float)
        self.store.append([data[0], data[1], data[2]])
        self.type = "vector"

    def return_data(self):
        store_data = []

        def iterate_over_data(model, path, itr):
            row = model[path]
            store_data.append([row[0], row[1], row[2]])

        self.store.foreach(iterate_over_data)

        return store_data

class DataSet(object):

    def __init__(self, name):
        self.name = name
        self.sets = []

    def add_vector(self):
        data = [random.randint(0,9) for x in range(3)]
        self.sets.append(Vector(data))

    def to_json(self):
        self.copy = []
        for s in self.sets:
            self.copy.append(s.return_data())

        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

obj1 = DataSet("dataset1")
for x in range(2):
    obj1.add_vector()

print(obj1.to_json())

Старый пример

В настоящее время я выясняю, как сериализовать Gtk ListStore, который вложен в Gtk TreeStore. У меня есть небольшой пример для работы, но я не уверен, будет ли этот подход масштабироваться для программ с большим количеством подключенных данных (например, объект слоя может содержать цвет или дату создания). Может быть, есть еще один способ сделать это?

Мой текущий подход заключается в сборе данных в списке и в форме словаря, а затем просто создайте JSON-дамп. У меня такое ощущение, что это будет довольно сложно поддерживать, если мне нужно прикрепить 25 значений к каждому слою-объекту.

from gi.repository import Gtk, Gdk
import json
import random


class LayerTreeView(Gtk.TreeView):

    def __init__(self, store):
        Gtk.TreeView.__init__(self, store)
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Name", renderer, text=0)
        self.append_column(column)


class DataTreeView(Gtk.TreeView):

    def __init__(self, store):
        Gtk.TreeView.__init__(self, store)
        self.store = store
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Data", renderer, text=0)
        self.append_column(column)


class MainWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="TreeView Serialize")
        self.connect("delete-event", Gtk.main_quit)
        self.set_border_width(10)
        self.set_default_size(400, 300)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True)
        self.add(vbox)

        self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
        button = Gtk.Button("Cut")
        button.connect("clicked", self.on_cut_clicked)
        hbox.pack_start(button, True, True, 0)

        button = Gtk.Button(stock=Gtk.STOCK_COPY)
        button.connect("clicked", self.on_copy_clicked)
        hbox.pack_start(button, True, True, 0)

        button = Gtk.Button(stock=Gtk.STOCK_PASTE)
        button.connect("clicked", self.on_paste_clicked)
        hbox.pack_start(button, True, True, 0)
        vbox.add(hbox)

        self.layer_store = Gtk.TreeStore(str, object, object)
        self.layer_view = LayerTreeView(self.layer_store)

        self.layer_sw = Gtk.ScrolledWindow()
        self.data_sw = Gtk.ScrolledWindow()
        self.layer_sw.add(self.layer_view)

        treebox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, expand=True)
        treebox.pack_start(self.layer_sw, True, True, 0)
        treebox.pack_start(self.data_sw, True, True, 0)
        vbox.add(treebox)

        self.select = self.layer_view.get_selection()
        self.select.connect("changed", self.on_selection_changed)

        self.add_test_data()

    def add_test_data(self):
        for x in range(3):
            data_store = Gtk.ListStore(str)
            data_view = DataTreeView(data_store)
            for y in range(5):
                data_store.append([str(y+x)])
            self.layer_store.append(None, ["Data {}".format(x), data_store, data_view])

    def on_selection_changed(self, selection):
        """
        When layer is switched load respective data
        """
        model, treeiter = selection.get_selected()
        if treeiter != None:
            data_view = model[treeiter][2]
            child = self.data_sw.get_child()
            if child != None:
                self.data_sw.remove(self.data_sw.get_child())
            self.data_sw.add(data_view)
            self.show_all()

    def on_cut_clicked(self, button):
        pass

    def on_copy_clicked(self, button):
        copy_list = ["safe-to-paste"]
        data_dict = {}
        for row in self.layer_store:
            name = row[0]
            data_obj = row[1]
            value_list = []
            for datarow in data_obj:
                value = datarow[0]
                value_list.append(value)
            data_dict[name] = value_list

        copy_list.append(data_dict)
        data = json.dumps(copy_list)
        self.clipboard.set_text(data, -1)

    def on_paste_clicked(self, button):
        paste_str = self.clipboard.wait_for_text()
        try:
            parse = json.loads(paste_str)
            json_str = True
        except:
            json_str = False

        if json_str is False:
            return

        keyword = parse[0]
        if keyword != "safe-to-paste":
            return

        data_dict = parse[1]
        for x in data_dict:
            data_list = data_dict[x]
            data_store = Gtk.ListStore(str)
            data_view = DataTreeView(data_store)
            for y in data_list:
                data_store.append([str(y)])
            self.layer_store.append(None, [x, data_store, data_view])

win = MainWindow()
win.show_all()
Gtk.main()
4b9b3361

Ответ 1

У меня улучшенная версия вашего кода с понятием dict и @staticmethod, что делает обратные вызовы сигналов более читабельными и короткими. Тем не менее, это на самом деле не решает вашу проблему, поскольку она все еще создает json вручную. Если ListStore становится более сложным, было бы лучше, если бы класс DataListStore сгенерировал собственный json с соответствующим методом.

from gi.repository import Gtk, Gdk
import json


class LayerTreeView(Gtk.TreeView):

    def __init__(self, store):
        Gtk.TreeView.__init__(self, store)
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Name", renderer, text=0)
        self.append_column(column)


class DataTreeView(Gtk.TreeView):

    def __init__(self):
        Gtk.TreeView.__init__(self)
        renderer = Gtk.CellRendererText()
        column = Gtk.TreeViewColumn("Data", renderer, text=0)
        self.append_column(column)

class DataListStore(Gtk.ListStore):

    @staticmethod
    def from_json(*args, values=[]):
        store = DataListStore(*args)
        for value in values:
            store.append((value,))
        return store


class MainWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="TreeView Serialize")
        self.connect("delete-event", Gtk.main_quit)
        self.set_border_width(10)
        self.set_default_size(400, 300)
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, expand=True)
        self.add(vbox)

        self.clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
        button = Gtk.Button("Cut")
        button.connect("clicked", self.on_cut_clicked)
        hbox.pack_start(button, True, True, 0)

        button = Gtk.Button(stock=Gtk.STOCK_COPY)
        button.connect("clicked", self.on_copy_clicked)
        hbox.pack_start(button, True, True, 0)

        button = Gtk.Button(stock=Gtk.STOCK_PASTE)
        button.connect("clicked", self.on_paste_clicked)
        hbox.pack_start(button, True, True, 0)
        vbox.add(hbox)

        self.layer_store = Gtk.TreeStore(str, object)
        self.layer_view = LayerTreeView(self.layer_store)
        self.data_view = DataTreeView()

        layer_sw = Gtk.ScrolledWindow()
        layer_sw.add(self.layer_view)
        data_sw = Gtk.ScrolledWindow()
        data_sw.add(self.data_view)

        treebox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6, expand=True)
        treebox.pack_start(layer_sw, True, True, 0)
        treebox.pack_start(data_sw, True, True, 0)
        vbox.add(treebox)

        select = self.layer_view.get_selection()
        select.connect("changed", self.on_selection_changed)

        self.add_test_data()

    def add_test_data(self):
        for x in range(3):
            data_list = [str(y+x) for y in range(5)]
            self.layer_store.append(None, ["Data {}".format(x), data_list])

    def on_selection_changed(self, selection):
        """
        When layer is switched load respective data
        """
        model, treeiter = selection.get_selected()
        if treeiter != None:
            self.data_view.set_model(
                DataListStore.from_json(str, values=model[treeiter][1])
            )

    def on_cut_clicked(self, button):
        pass

    def on_copy_clicked(self, button):
        copy_list = [
            'safe-to-paste',
            {row[0]: row[1] for row in self.layer_store},
        ]
        data = json.dumps(copy_list)
        self.clipboard.set_text(data, -1)

    def on_paste_clicked(self, button):
        paste_str = self.clipboard.wait_for_text()
        try:
            parse = json.loads(paste_str)
        except:
            return

        if parse[0] != "safe-to-paste":
            return

        data_dict = parse[1]
        for x in data_dict:
            self.layer_store.append(None, [x, data_dict[x]])

win = MainWindow()
win.show_all()
Gtk.main()