图元的拖拽及连线这类操作在一些桌面软件中很是常见。比如在学校用的eNSP(如下图),很直观,图元代表模型,连线代表连接(或关系)。本文就从头开始,实现这些功能,效果也如下图。

1. 背景搭建
纯色背景
建立图元首先要有一个“画板”。
import sys
from PyQt5.QtWidgets import QApplication, QGraphicsScene, QGraphicsView
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.scene = QGraphicsScene(self)
self.view = QGraphicsView(self)
# 有view就要有scene
self.view.setScene(self.scene)
# 设置view可以进行鼠标的拖拽选择
self.view.setDragMode(self.view.RubberBandDrag)
self.setMinimumHeight(500)
self.setMinimumWidth(500)
self.setCentralWidget(self.view)
self.setWindowTitle("Graphics Demo")
def demo_run():
app = QApplication(sys.argv)
demo = MainWindow()
# 适配 Retina 显示屏(选写).
app.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app.setAttribute(Qt.AA_EnableHighDpiScaling, True)
# ----------------------------------
demo.show()
sys.exit(app.exec_())
if __name__ == '__main__':
demo_run()
此时运行,效果如下。背景是白色的,蓝色的区域是我用鼠标拖拽时产生的。多少有些不美观,这样,我们换个背景。换一个稍微看起来高大上一些的背景。

网格背景
这样一来,就需要重写QGraphicsScene类中一个名为drawBackground的方法。顾名思义,该方法是画背景用的。此时我们单独建立一个类,继承它并重写方法。
import math
from PyQt5.QtWidgets import QGraphicsScene
from PyQt5.QtGui import QColor, QPen
from PyQt5.QtCore import QLine
class GraphicScene(QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
# 一些关于网格背景的设置
self.grid_size = 20 # 一块网格的大小 (正方形的)
self.grid_squares = 5 # 网格中正方形的区域个数
# 一些颜色
self._color_background = QColor('#393939')
self._color_light = QColor('#2f2f2f')
self._color_dark = QColor('#292929')
# 一些画笔
self._pen_light = QPen(self._color_light)
self._pen_light.setWidth(1)
self._pen_dark = QPen(self._color_dark)
self._pen_dark.setWidth(2)
# 设置画背景的画笔
self.setBackgroundBrush(self._color_background)
self.setSceneRect(0, 0, 500, 500)
# override
def drawBackground(self, painter, rect):
super().drawBackground(painter, rect)
# 获取背景矩形的上下左右的长度,分别向上或向下取整数
left = int(math.floor(rect.left()))
right = int(math.ceil(rect.right()))
top = int(math.floor(rect.top()))
bottom = int(math.ceil(rect.bottom()))
# 从左边和上边开始
first_left = left - (left % self.grid_size) # 减去余数,保证可以被网格大小整除
first_top = top - (top % self.grid_size)
# 分别收集明、暗线
lines_light, lines_dark = [], []
for x in range(first_left, right, self.grid_size):
if x % (self.grid_size * self.grid_squares) != 0:
lines_light.append(QLine(x, top, x, bottom))
else:
lines_dark.append(QLine(x, top, x, bottom))

最低0.47元/天 解锁文章
206

被折叠的 条评论
为什么被折叠?



