IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(23)——实现剪贴板功能 -> 正文阅读

[C++知识库][PyQt5-Node-Editor][进阶篇]使用Pyqt5制作节点编辑器(23)——实现剪贴板功能

目标

请添加图片描述

实现剪贴板功能

实现

剪贴板完整代码

from collections import OrderedDict
from node_graphics_edge import QDMGraphicsEdge
from node_node import Node
from node_edge import Edge, EDGE_TYPE_BEZIER

DEBUG = False

class SceneClipboard():
    def __init__(self,scene):
        self.scene = scene

    def serializeSelected(self, delete=False):
        if DEBUG: print("---复制到剪贴板---")


        sel_nodes, sel_edges, sel_sockets = [], [], {}


        for item in self.scene.grScene.selectedItems():
            if hasattr(item,'node'):
                sel_nodes.append(item.node.serialize())
                for socket in (item.node.inputs + item.node.outputs):
                    sel_sockets[socket.id] = socket

            elif isinstance(item, QDMGraphicsEdge):
                sel_edges.append(item.edge)


        if DEBUG:
            print("   NODES\n       ", sel_nodes)
            print("   EDGES\n       ", sel_edges)
            print("   SOCKETS\n       ", sel_sockets)

        edges_to_remove = []
        for edge in sel_edges:
            if edge.start_socket.id in sel_sockets and edge.end_socket.id in sel_sockets:
                pass
            else:
                if DEBUG: print("edge", edge, "它未连接")
                edges_to_remove.append(edge)

        for edge in edges_to_remove:
            sel_edges.remove(edge)


        edges_final = []
        for edge in sel_edges:
            edges_final.append(edge.serialize())


        data = OrderedDict([
            ('nodes', sel_nodes),
            ('edges', edges_final),
        ])

        if delete:
            self.scene.grScene.views()[0].deleteSelected()
            # 存储历史
            self.scene.history.storeHistory("剪切")

        return data

    def deserializeFromClipboard(self, data):
        hashmap = {}

        # 计算鼠标在场景中位置
        view = self.scene.grScene.views()[0]
        mouse_scene_pos = view.last_scene_mouse_position

        # 计算复制被选中对象的中心
        minx, maxx, miny, maxy = 0,0,0,0
        for node_data in data['nodes']:
            x, y = node_data['pos_x'], node_data['pos_y']
            if x < minx: minx = x
            if x > maxx: maxx = x
            if y < miny: miny = y
            if y > maxy: maxy = y
        bbox_center_x = (minx + maxx) / 2
        bbox_center_y = (miny + maxy) / 2

        # center = view.mapToScene(view.rect().center())


        # 计算新建节点中心点位置
        offset_x = mouse_scene_pos.x() - bbox_center_x
        offset_y = mouse_scene_pos.y() - bbox_center_y

        # 创建节点
        for node_data in data['nodes']:
            new_node = Node(self.scene)
            new_node.deserialize(node_data, hashmap, restore_id=False)

            # 新节点位置
            pos = new_node.pos
            new_node.setPos(pos.x() + offset_x, pos.y() + offset_y)

        # 创建Edge
        if 'edges' in data:
            for edge_data in data['edges']:
                new_edge = Edge(self.scene)
                new_edge.deserialize(edge_data, hashmap, restore_id=False)

        # 存储历史
        self.scene.history.storeHistory("粘贴")

复制到剪贴板

    def serializeSelected(self, delete=False):
        if DEBUG: print("---复制到剪贴板---")

        sel_nodes, sel_edges, sel_sockets = [], [], {}

        for item in self.scene.grScene.selectedItems():
            if hasattr(item, 'node'):
                sel_nodes.append(item.node.serialize())
                for socket in (item.node.inputs + item.node.outputs):
                    sel_sockets[socket.id] = socket

            elif isinstance(item, QDMGraphicsEdge):
                sel_edges.append(item.edge)

        if DEBUG:
            print("   NODES\n       ", sel_nodes)
            print("   EDGES\n       ", sel_edges)
            print("   SOCKETS\n       ", sel_sockets)

        edges_to_remove = []
        for edge in sel_edges:
            if edge.start_socket.id in sel_sockets and edge.end_socket.id in sel_sockets:
                pass
            else:
                if DEBUG: print("edge", edge, "它未连接")
                edges_to_remove.append(edge)

        for edge in edges_to_remove:
            sel_edges.remove(edge)

        edges_final = []
        for edge in sel_edges:
            edges_final.append(edge.serialize())

        data = OrderedDict([
            ('nodes', sel_nodes),
            ('edges', edges_final),
        ])

        if delete:
            self.scene.grScene.views()[0].deleteSelected()
            # 存储历史
            self.scene.history.storeHistory("剪切")

        return data

先通过向sel_nodes, sel_edges, sel_sockets = [], [], {}这两个数组,一个字典里添加被选中对象以及ID
接着

        edges_to_remove = []
        for edge in sel_edges:
            if edge.start_socket.id in sel_sockets and edge.end_socket.id in sel_sockets:
                pass
            else:
                if DEBUG: print("edge", edge, "它未连接")
                edges_to_remove.append(edge)

        for edge in edges_to_remove:
            sel_edges.remove(edge)

        edges_final = []
        for edge in sel_edges:
            edges_final.append(edge.serialize())

来删除被选中的edge中,有未完全连接上的edge,比如
在这里插入图片描述

接着使用

        data = OrderedDict([
            ('nodes', sel_nodes),
            ('edges', edges_final),
        ])

        if delete:
            self.scene.grScene.views()[0].deleteSelected()
            # 存储历史
            self.scene.history.storeHistory("剪切")

来打包被选中的node和edge,并且通过传入的参数delete来判断原选择项是否需要被删除

粘贴

完整代码

    def deserializeFromClipboard(self, data):
        hashmap = {}

        # 计算鼠标在场景中位置
        view = self.scene.grScene.views()[0]
        mouse_scene_pos = view.last_scene_mouse_position

        # 计算复制被选中对象的中心
        minx, maxx, miny, maxy = 0, 0, 0, 0
        for node_data in data['nodes']:
            x, y = node_data['pos_x'], node_data['pos_y']
            if x < minx: minx = x
            if x > maxx: maxx = x
            if y < miny: miny = y
            if y > maxy: maxy = y
        bbox_center_x = (minx + maxx) / 2
        bbox_center_y = (miny + maxy) / 2

        # center = view.mapToScene(view.rect().center())

        # 计算新建节点中心点位置
        offset_x = mouse_scene_pos.x() - bbox_center_x
        offset_y = mouse_scene_pos.y() - bbox_center_y

        # 创建节点
        for node_data in data['nodes']:
            new_node = Node(self.scene)
            new_node.deserialize(node_data, hashmap, restore_id=False)

            # 新节点位置
            pos = new_node.pos
            new_node.setPos(pos.x() + offset_x, pos.y() + offset_y)

        # 创建Edge
        if 'edges' in data:
            for edge_data in data['edges']:
                new_edge = Edge(self.scene)
                new_edge.deserialize(edge_data, hashmap, restore_id=False)

        # 存储历史
        self.scene.history.storeHistory("粘贴")

先计算被选中整体的中心坐标
接着计算当前鼠标位置与被选中整体的位置差值
接着使用原坐标+位置差值,即可得使复制项整体的中心坐标落在鼠标位置
并且通过使用 restore_id=False创建新的对象

修个BUG

将View的鼠标中键释放事件的最后一行进行修改

    def middleMouseButtonRelease(self, event):
        fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(),
                                Qt.LeftButton, event.buttons() | Qt.LeftButton, event.modifiers())
        super().mouseReleaseEvent(fakeEvent)
        # 修改
        self.setDragMode(QGraphicsView.RubberBandDrag)

原来的代码,在鼠标中键移动后就不能框选

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 11:53:50  更:2021-07-26 11:56:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/23 19:14:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码