在第一篇博客中,我们已经完成了 PyQtNode Editor 的基础环境搭建,并深入解析了自定义图形场景QDMGraphicsScene的实现原理。那个带有网格背景的场景就像一张空白的图纸,现在我们要在这张图纸上开始绘制真正的节点系统。
今天我们将聚焦于节点编辑器的核心数据结构设计,实现 “节点类” 与 “图形节点类” 的分离,并完成第一个可交互节点的创建。这一步是整个编辑器的骨架,就像建造房屋时搭建承重结构一样关键。
一、自定义可视化视图函数
创建一个node_graphic_view.py文件
在 PyQtNode Editor 的开发过程中,图形视图的设置对于用户最终看到的界面效果和操作体验至关重要。接下来,我们深入解析QDMGraphicsView类的代码,看看它是如何定制图形场景的显示与交互的。
导入必要的模块
from PyQt5.QtWidgets import QGraphicsView
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QGraphicsView:从PyQt5.QtWidgets模块中导入QGraphicsView类。QGraphicsView是 PyQt5 中用于显示QGraphicsScene(图形场景)的视图类,它就像是一个 “画框”,可以将在场景中绘制的图形、节点等内容展示出来,并且提供了缩放、滚动等与图形交互的功能基础。
from PyQt5.QtCore import *:导入PyQt5.QtCore模块中的所有内容。这个模块包含了 PyQt5 的核心功能,例如信号与槽机制、定时器、元对象系统等,这些功能为图形视图的事件处理、状态管理等提供底层支持 。
from PyQt5.QtGui import *:导入PyQt5.QtGui模块中的所有内容。该模块主要用于处理图形相关的操作,比如绘制图形、设置画笔和画刷样式、处理字体等,是实现图形视图美观显示效果的关键。
定义 QDMGraphicsView 类
class QDMGraphicsView(QGraphicsView):
这里定义了一个名为QDMGraphicsView的类,它继承自QGraphicsView。继承的作用在于,QDMGraphicsView类可以复用QGraphicsView类已有的功能,同时在此基础上添加或修改特定的功能,以满足 PyQtNode Editor 项目中对于图形视图的个性化需求。
、
def __init__(self, grScene, parent=None):super().__init__(parent)self.grScene = grScene
self.initUI()
self.setScene(self.grScene)
super().init(parent):调用父类QGraphicsView的初始化方法,确保父类的属性和行为得到正确的初始化,就像建造房子时先搭建好基本的框架结构。
self.grScene = grScene:将传入的图形场景对象grScene赋值给当前类的实例属性self.grScene。这样,QDMGraphicsView类的实例就与特定的图形场景建立了关联,后续视图展示的内容就是这个场景中的元素。
self.initUI():调用自定义的initUI方法,用于对图形视图进行一些个性化的设置,比如渲染效果、滚动条策略等。
self.setScene(self.grScene):将之前保存的图形场景对象self.grScene设置为当前图形视图要显示的场景。这一步就像是把一幅画放入画框中,图形视图会将场景中的图形、节点等内容展示出来供用户查看和交互。
def initUI(self):self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform):通过setRenderHints方法设置图形渲染的提示选项。这里使用了按位或操作组合了多个渲染提示:
QPainter.Antialiasing:启用抗锯齿功能,使绘制的图形边缘更加平滑,避免出现锯齿状。
QPainter.HighQualityAntialiasing:进一步提高抗锯齿的质量,让图形看起来更加精美。
QPainter.TextAntialiasing:对文本进行抗锯齿处理,保证显示的文字清晰、美观。
QPainter.SmoothPixmapTransform:使图像在缩放或变换时更加平滑,避免出现模糊或失真的情况。
self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate):使用setViewportUpdateMode方法设置视图端口的更新模式为QGraphicsView.FullViewportUpdate。这意味着每当场景发生变化时,整个视图端口都会被更新。虽然这种方式在性能上可能不如其他更精细的更新模式,但可以确保视图显示的内容始终是最新和完整的。
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)和self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff):分别设置水平和垂直滚动条的策略为Qt.ScrollBarAlwaysOff,即始终隐藏滚动条。这表明在当前的设计中,不希望用户通过滚动条来滚动视图,可能是因为场景的尺寸设置以及整体交互设计不需要滚动条,或者后续会通过其他方式(如鼠标滚轮缩放等)来实现对场景的浏览。
完整代码node_graphic_view.py
# 导入PyQt5的QGraphicsView类,用于显示和操作QGraphicsScene中的内容
from PyQt5.QtWidgets import QGraphicsView
# 导入PyQt5的核心模块,包含信号与槽、事件系统等基础功能
from PyQt5.QtCore import *
# 导入PyQt5的GUI模块,包含绘图、字体、颜色等图形相关功能
from PyQt5.QtGui import *# 自定义图形视图类,继承自QGraphicsView,用于显示和操作节点编辑器的图形场景
class QDMGraphicsView(QGraphicsView):# 类的构造函数,接收图形场景对象和可选的父对象def __init__(self, grScene, parent=None):# 调用父类的构造函数完成初始化super().__init__(parent)# 保存传入的图形场景对象的引用self.grScene = grScene# 初始化用户界面设置self.initUI()# 将图形场景设置到视图中,使视图显示该场景的内容self.setScene(self.grScene)# 初始化用户界面的方法,设置视图的各种属性和行为def initUI(self):# 设置渲染提示,启用多项抗锯齿和高质量渲染选项:# - Antialiasing:平滑图形边缘,减少锯齿# - HighQualityAntialiasing:使用更高质量的抗锯齿算法# - TextAntialiasing:平滑文本边缘,提高可读性# - SmoothPixmapTransform:平滑处理缩放和变换后的像素图self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)# 设置视图更新模式为完全更新,每次场景变化时重绘整个视图# 这种模式确保显示效果一致,但可能影响性能self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)# 设置水平滚动条策略为始终关闭,不显示水平滚动条self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)# 设置垂直滚动条策略为始终关闭,不显示垂直滚动条self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
二、调用自定义视图函数
回到node_graphic_wnd.py文件
导入我们自定义的画布样式:
from node_graphics_view import QDMGraphicsView
然后对原来系统的标准视图更改成我们自定义的视图:
这个是原来的
self.view = QGraphicsView(self)
self.view.setScene(self.grScene)
更改后的:
self.view = QDMGraphicsView(self.grScene, self)
然后添加一个addDebugContent()方法向场景中添加了多种图形元素用于测试:
def addDebugContent(self):# 创建绿色画刷和黑色轮廓画笔greenBrush = QBrush(Qt.green)outlinePen = QPen(Qt.black)outlinePen.setWidth(2)# 添加可移动的矩形rect = self.grScene.addRect(-100, -100, 80, 100, outlinePen, greenBrush)rect.setFlag(QGraphicsItem.ItemIsMovable)# 添加可选择和移动的文本text = self.grScene.addText("This is my Awesome text!", QFont("Ubuntu"))text.setFlag(QGraphicsItem.ItemIsSelectable)text.setFlag(QGraphicsItem.ItemIsMovable)text.setDefaultTextColor(QColor.fromRgbF(1.0, 1.0, 1.0))# 添加可移动的按钮控件widget1 = QPushButton("Hello World")proxy1 = self.grScene.addWidget(widget1)proxy1.setFlag(QGraphicsItem.ItemIsMovable)proxy1.setPos(0, 30)# 添加可选择的文本编辑控件widget2 = QTextEdit()proxy2 = self.grScene.addWidget(widget2)proxy2.setFlag(QGraphicsItem.ItemIsSelectable)proxy2.setPos(0, 60)# 添加可选择和移动的线条line = self.grScene.addLine(-200, -200, 400, -100, outlinePen)line.setFlag(QGraphicsItem.ItemIsMovable)line.setFlag(QGraphicsItem.ItemIsSelectable)
最终完整的node_graphic_wnd.py文件
# 从PyQt5的QtWidgets模块导入所有的类和函数,该模块包含各种用于创建用户界面的组件,如窗口、按钮、布局等
from PyQt5.QtWidgets import *
# 从PyQt5的QtGui模块导入所有的类和函数,此模块用于处理图形相关操作,如画笔、画刷、字体、绘图等功能
from PyQt5.QtGui import *
# 从PyQt5的QtCore模块导入所有的类和函数,该模块提供了PyQt5的核心功能,包括信号与槽机制、事件循环、定时器等
from PyQt5.QtCore import *# 从自定义模块node_graphics_scene中导入QDMGraphicsScene类,该类用于创建自定义的图形场景
from node_graphics_scene import QDMGraphicsScene