[PyQt5] 实现图元(QGraphicsItem)的建立、操作和连接

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

此时运行,效果如下。背景是白色的,蓝色的区域是我用鼠标拖拽时产生的。多少有些不美观,这样,我们换个背景。换一个稍微看起来高大上一些的背景。
效果1

网格背景

这样一来,就需要重写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))
		
        
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值