[PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(16)——序列化,保存Scene

导航

目标

能够将scene数据保存为一个JSON文件,方便读取和保存

{
    "id": 2586028185080,
    "scene_width": 64000,
    "scene_height": 64000,
    "node": [
        {
            "id": 2586029654760,
            "title": "这是一个节点",
            "pos_x": -350.0,
            "pos_y": -250.0,
            "inputs": [
                {
                    "id": 2586029897152,
                    "index": 0,
                    "position": 2,
                    "socket_type": 0
                },
                {
                    "id": 2586029905288,
                    "index": 1,
                    "position": 2,
                    "socket_type": 0
                },
                {
                    "id": 2586029905344,
                    "index": 2,
                    "position": 2,
                    "socket_type": 0
                }
            ],
            "outputs": [
                {
                    "id": 2586029905400,
                    "index": 0,
                    "position": 3,
                    "socket_type": 3
                }
            ],
            "content": {}
        },
        {
            "id": 2586029897096,
            "title": "这是第二个节点",
            "pos_x": -75.0,
            "pos_y": 0.0,
            "inputs": [
                {
                    "id": 2586029905512,
                    "index": 0,
                    "position": 2,
                    "socket_type": 1
                },
                {
                    "id": 2586029905568,
                    "index": 1,
                    "position": 2,
                    "socket_type": 1
                },
                {
                    "id": 2586029905624,
                    "index": 2,
                    "position": 2,
                    "socket_type": 1
                }
            ],
            "outputs": [
                {
                    "id": 2586029905680,
                    "index": 0,
                    "position": 3,
                    "socket_type": 3
                }
            ],
            "content": {}
        },
        {
            "id": 2586029905456,
            "title": "这是第三个节点",
            "pos_x": 200.0,
            "pos_y": -150.0,
            "inputs": [
                {
                    "id": 2586029905792,
                    "index": 0,
                    "position": 2,
                    "socket_type": 2
                },
                {
                    "id": 2586029905848,
                    "index": 1,
                    "position": 2,
                    "socket_type": 2
                },
                {
                    "id": 2586029905904,
                    "index": 2,
                    "position": 2,
                    "socket_type": 2
                }
            ],
            "outputs": [
                {
                    "id": 2586029905960,
                    "index": 0,
                    "position": 3,
                    "socket_type": 3
                }
            ],
            "content": {}
        }
    ],
    "edges": [
        {
            "id": 2586029905736,
            "edge_type": 2,
            "start": 2586029905400,
            "end": 2586029905512
        },
        {
            "id": 2586061985944,
            "edge_type": 2,
            "start": 2586029905680,
            "end": 2586029905904
        }
    ]
}

实现

建立一个序列化父模板

目前,我们建立了Node,Scene,Socket,Edge,Content这些类,
如果要想获取这些类的信息,存储到json文件里去,那么就需要这些类能够自己将自己的属性序列化
于是,我们可以写一个类来实现序列化功能,这个类作为父类,其他的类继承这个父类,并对其序列化操作进行改写

class Serializable():
    def __init__(self):
        self.id = id(self)

    def serialize(self):
        raise NotImplemented()

    def deserialize(self, data, hashmap=[]):
        raise NotImplemented()

其中serialize用于编码,并返回编码,deserialize负责解码,deserialize的功能放在下一篇写

Scene序列化

[PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(16)——序列化,保存Scene
我们将导入这三个包,并且让Scene继承Serializable
随后改写serialize,deserialize

    def serialize(self):
        nodes, edges = [],[]
        for node in self.nodes:
            nodes.append(node.serialize())
        for edge in self.edges:
            edges.append(edge.serialize())
        return OrderedDict([
            ('id',self.id),
            ('scene_width',self.scene_width),
            ('scene_height',self.scene_height),
            ('node',nodes),
            ('edges',edges),
        ])

    def deserialize(self, data, hashmap=[]):
        print('解码数据', data)
        return False

Scene为最外层,node和edge是下一层,socket和content是node下的层
于是要获取node和edge的序列化信息,就需要调用
node.serialize()
edge.serialize()
除此之外,我将读取和保存的代码写在了Scene里

    def saveToFile(self, filename):
        with open(filename, 'w') as file:
            file.write(json.dumps(self.serialize(), indent=4, ensure_ascii=False))
        print(filename, "保存成功")

    def loadFromFlie(self, filename):
        with open(filename, 'r') as file:
            raw_data = file.read()
            data = json.loads(raw_data, encoding='utf-8')
            self.deserialize(data)

它将根据self.serialize()返回的值来保存JSON文件

Edge序列化

同理继承,后面都需要继承
[PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(16)——序列化,保存Scene

    def serialize(self):
        return OrderedDict([
            ('id',self.id),
            ('edge_type', self.edge_type),
            ('start', self.start_socket.id),
            ('end', self.end_socket.id),
        ])

    def deserialize(self, data, hashmap=[]):
        print('解码数据', data)
        return False

Node序列化

    def serialize(self):
        inputs, outputs = [], []
        for socket in self.inputs:
            inputs.append(socket.serialize())
        for socket in self.outputs:
            outputs.append(socket.serialize())
        return OrderedDict([
            ('id', self.id),
            ('title', self.title),
            ('pos_x', self.grNode.scenePos().x()),
            ('pos_y', self.grNode.scenePos().y()),
            ('inputs', inputs),
            ('outputs', outputs),
            ('content', self.content.serialize())
        ])

    def deserialize(self, data, hashmap=[]):
        print('解码数据', data)
        return False

由于由于调用了
socket.serialize()
content.serialize()
来获取序列化信息,所以需要写他们两个的序列化

Socket序列化

    def serialize(self):
        return OrderedDict([
            ('id',self.id),
            ('index', self.index),
            ('position', self.position),
            ('socket_type', self.socket_type),

        ])

    def deserialize(self, data, hashmap=[]):
        print('解码数据', data)
        return False

Content序列化

其中Content比较特殊,要继承Serializable,直接添加父类继承即可
[PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(16)——序列化,保存Scene

    def serialize(self):
        return OrderedDict([

        ])

    def deserialize(self, data, hashmap=[]):
        return False

这里我们只返回一个空列表,以后再来写

View里保存和读取

到View里的键入事件里,添加如下代码

def keyPressEvent(self, event):
    if event.key() == Qt.Key_Delete:
        if not self.editingFlag:
            self.deleteSelected()
        else:
            super().keyPressEvent(event)
    elif event.key() == Qt.Key_S and event.modifiers() & Qt.ControlModifier:
        self.grScene.scene.saveToFile('graph.json')
    elif event.key() == Qt.Key_L and event.modifiers() & Qt.ControlModifier:
        self.grScene.scene.loadFromFlie('graph.json')
    else:
        super().keyPressEvent(event)

按下Crtl+S保存,按下Crtl+L进行读取
保存后既可以看到目录下生成graph.json文件

上一篇:DataSet Serialize


下一篇:文档与串行化