第15.47节、PyQt显示部件:QGraphicsView图形视图和QGraphicsScene图形场景简介及应用案例

一、概述

Designer中的Graphics View部件是个图形视图部件,对应类为QGraphicsView,其功能不是简单的显示图形,老猿认为这是一种特殊的视图,它与QGraphicsScene配套实现了类似Model/View的架构。

本节不介绍QGraphicsView和QGraphicsScene的所有属性、方法,大家可以参考官方文档,另外老猿推荐《Qt绘图之QGraphicsScene QGraphicsView QGraphicsItem详解》供大家参考。

二、QGraphicsView功能简介

QGraphicsView主要是用于界面显示图形的,显示的内容由QGraphicsScene决定。QGraphicsView支持鼠标的拖拽、点击、滚动等事件,可以根据滚动条策略控制滚动条的出现,提供视图、场景的坐标映射,支持设置对齐方式。

具体属性、方法、信号可以参考官方文档以及上面推荐的博文,在此需要重点说明如下几点:

  1. QGraphicsView默认是带有内边距和边界,会导致内置于内的QGraphicsScene坐标与视图看到的效果不一致,具体请参考《QT:QGraphicsView QGraphicsScene QGraphicsItem理解
  2. QGraphicsView的坐标体系与QWidget的坐标体系相同,视口范围需要从其viewport视口属性获取
  3. QGraphicsView的场景可以从scene()方法获取,场景大小范围可以从sceneRect()获取
  4. QGraphicsView的默认是居中对齐的,所以如果添加显示对象,默认是显示在中央的

三、QGraphicsScene功能简介

QGraphicsScene用于管理一个需要绘制的图形对象,每个对象称为图元(基类为QGraphicsItem),如果理解QGraphicsScene为一个Model对象的话,QGraphicsItem就是Model中的项。

QGraphicsItem具体属性、方法、信号可以参考官方文档以及上面推荐的博文,在此需要重点说明如下几点:

  1. QGraphicsScene的图元类型有多种,每种图元在添加时要调用专属的添加方法,方法会返回对应的图元类型对象。这些方法包括addLine()、addPath()、addPixmap()、 addRect()、 addText()、addEllipse()、addPolygon()、addSimpleText等
  2. QGraphicsScene的图元都可以通过setPos方法改变其位置,但需要注意,QGraphicsScene的坐标体系与QGraphicsView不同,具体请参考前面推荐的博文
  3. QGraphicsScene提供了大多数的鼠标和键盘等事件处理虚方法,如mousePressEvent、mouseMoveEvent、mouseReleaseEvent、mouseDoubleClickEvent、keyReleaseEvent、keyPressEvent等,可以通过子类化或者动态赋值方式接管相关的事件处理,从而实现对应的处理。但需要注意的是,这些方法中鼠标的位置应该通过scenePos()来获取,不能通过pos()来获取,pos是仅当鼠标点击了对应图元的时候才有值

四、案例

4.1、案例功能说明

在案例中需要在界面上显示如下内容:
在这里插入图片描述
并实现除HELLO外的部分随鼠标点击移动位置。上面的内容包括图片、文字、直线、椭圆以及曲线。

4.2、界面设计

界面UI设计非常简单,就是一个窗口中放置了一个QGraphicsView,如图:
在这里插入图片描述
窗口命名为mainWin,图形视图命名为graphicsView。

4.3、实现界面派生类构造方法

构造方法中除了图形界面初始化外,还将图形视图的内边距和边界去除、改变图形视图的对齐方式、设置场景大小和图形视图大小一致,并绘制图形,同时接管图形场景的mousePressEvent 方法。具体代码如下:

class mainWin(QtWidgets.QWidget,ui_mainWin.Ui_mainWin):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.graphicsView.setStyleSheet("padding: 0px; border: 0px;")#内边距和边界去除
        self.scene = QtWidgets.QGraphicsScene(self)
        self.graphicsView.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) #改变对齐方式

        self.graphicsView.setSceneRect(0,0,self.graphicsView.viewport().width(),self.graphicsView.height()) #设置图形场景大小和图形视图大小一致
        self.graphicsView.setScene(self.scene)
        self.addScenes() #调用绘制图形的方法
        self.scene.mousePressEvent = self.mousePressEvent  #接管图形场景的鼠标事件
4.4、实现绘制图形的addScenes方法
    def addScenes(self): #绘制图形
        originX,originY = 40,60  #坐标基点
        self.itemHELLO = self.scene.addText("HELLO!")  #输出hello
        self.itemHELLO.setPos(0, 0)

        #绘制矩形
        pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.red))
        rectF = QtCore.QRectF(originX+300-8, originY-25, 20, 50)
        self.elpItem = self.scene.addEllipse(rectF, pen)

        # 绘制曲线
        pen.setColor(QtGui.QColor(QtCore.Qt.blue))
        path = QtGui.QPainterPath()
        path.moveTo(originX,originY)
        path.cubicTo(originX+100, originY-150, originX+200, originY+150,originX+300,originY)
        myGradient = QtGui.QLinearGradient()
        myFont = QtGui.QFont()
        textPoint = QtCore.QPointF(originX+35,originY-4)
        path.addText(textPoint, myFont, "老猿Python")
        self.itemPath = self.scene.addPath(path,pen,myGradient)
        #绘制下划线
        pen.setColor(QtGui.QColor(QtCore.Qt.darkRed))
        line = QtCore.QLineF(QtCore.QPointF(originX+190, originY-20), QtCore.QPointF(originX+275, originY-20))
        self.itemLine = self.scene.addLine(line, pen)
        self.itemLine.setPos(0,originY-20)

        #绘制文字
        self.itemText = self.scene.addText("跟老猿学Python!")
        self.itemText.setPos(originX+185,originY+1)
        
        #绘制图片
        pixmap = QtGui.QPixmap(r"F:\coffeDog\咖啡狗小图.jpg")
        self.pixmapItem = self.scene.addPixmap(pixmap)
        self.pixmapItem.setPos(originX-34,originY-16)
        
        #绘制x轴
        pen.setColor(QtGui.QColor(QtCore.Qt.red))
        self.xLine = self.scene.addLine(originX,originY, originX+300, originY, pen)
4.5、实现鼠标按键响应myMousePressEvent方法

注意这个方法不要命名为mousePressEvent,因为这样不但会接管图形场景的鼠标按键事件,而且会接管主窗口的鼠标按键事件,而二者的参数类型是不同的,对应属性也不同。

    def myMousePressEvent(self,mouseEvent):
        print("myMousePressEvent",mouseEvent.type(),mouseEvent.scenePos())
        point = mouseEvent.scenePos()
        if  point:
            self.movePath(point) #移动相关图元,方法单独实现
        else:print("not valid point")
4.6、实现图元移动的movePath方法

在该方法中需要将相关图元的位置同步移动,所以在绘制方法中记录下来了所有图元对象。移动图元是参考图片的坐标。

4.7、运行效果

在这里插入图片描述

广告

老猿关于PyQt的付费专栏《使用PyQt开发图形界面Python应用》只需要9.9元,该部分与第十五章的内容基本对应,但同样内容在付费专栏上总体来说更详细、案例更多。本节内容对应付费专栏的《第四十章、PyQt显示部件:QGraphicsView图形视图和QGraphicsScene图形场景简介及应用案例
》。如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python、学5G!

<think>好的,用户想学习PyQt6中QGraphicsViewQGraphicsScene的用法,需要教程示例代码。首先,我需要整理这两个组件的基本结构层级关系。根据引用内容,QGraphicsView是视图,包含QGraphicsScene场景,而场景中又包含各种图形项,比如矩形、椭圆、文本等[^1]。 接下来,用户可能需要基础的示例代码来理解如何创建场景视图。查看引用中的例子,比如引用3中的代码,可以展示如何初始化场景、视图,并添加简单的图形项。但要注意用户使用的是PyQt6,可能需要调整导入语句,比如将PySide6改为PyQt6的模块。 然后,需要介绍如何添加不同类型的图形项,比如椭圆、文本,以及自定义项。这部分需要确保使用正确的类方法,比如addEllipse、addText等。同时,自定义项可能需要继承QGraphicsItem并重写paintboundingRect方法,但根据引用2中的建议,更推荐使用现有的图形项,除非有必要自定义。 用户可能还关心如何实现交互功能,比如鼠标事件。引用4提到了如何处理鼠标点击事件,可以通过子类化QGraphicsView并重写mousePressEvent来实现。这部分需要详细说明,并提供示例代码,确保用户能够实现交互效果。 另外,动画刷新机制也是常见需求。引用4中的QPixmap更新可能涉及定时器场景更新方法,比如使用QTimer定时调用update,然后重写paint事件。需要给出一个简单的动画示例,比如移动矩形,展示如何通过定时器修改位置并刷新视图。 最后,整理常见问题使用技巧,比如坐标系的理解、性能优化(大量图形项的处理)、事件传递机制等,帮助用户避免常见陷阱。确保引用相关文献,如引用1的结构引用3的示例代码,增强回答的可信度。 检查所有代码是否符合PyQt6的语法,比如导入语句是否正确,方法名是否有变化。同时,确保所有数学公式变量使用$...$格式,独立公式用$$...$$,但当前问题不涉及数学公式,可能不需要处理这部分。 总结回答的结构,先介绍组件层级,再分步讲解基础使用、图形项添加、交互、动画,最后注意事项。确保每个部分都有代码示例引用支持,语言简洁明了,符合中文表达习惯。</think>### PyQt6 QGraphicsView QGraphicsScene 使用教程 #### 一、组件层级与基本概念 PyQt6 中的图形视图框架由三部分组成: - **QGraphicsView**(视图):负责显示场景内容,支持缩放、旋转等交互操作[^1]。 - **QGraphicsScene**(场景):管理图形项的容器,处理事件传播坐标变换[^2]。 - **QGraphicsItem**(图形项):如矩形、椭圆、文本等,支持自定义绘制[^1]。 #### 二、基础使用示例 以下代码演示如何创建场景视图,并添加一个矩形: ```python from PyQt6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsRectItem from PyQt6.QtCore import Qt app = QApplication([]) # 创建场景视图 scene = QGraphicsScene() view = QGraphicsView(scene) view.setWindowTitle("基础示例") # 添加矩形项 rect = scene.addRect(0, 0, 100, 50) # (x, y, width, height) rect.setBrush(Qt.GlobalColor.blue) # 设置填充颜色 view.show() app.exec() ``` 此代码会显示一个蓝色矩形,视图默认大小为 640x480[^3]。 #### 三、添加不同类型图形项 1. **椭圆与文本** ```python # 添加椭圆 ellipse = scene.addEllipse(50, 50, 80, 60, brush=Qt.GlobalColor.red) # 添加文本 text = scene.addText("Hello PyQt6") text.setPos(100, 100) # 设置文本位置 ``` 2. **自定义图形项** ```python class CustomItem(QGraphicsRectItem): def paint(self, painter, option, widget=None): painter.drawRect(self.rect()) painter.drawText(20, 20, "自定义项") custom_item = CustomItem(0, 0, 120, 80) scene.addItem(custom_item) ``` #### 四、交互与事件处理 实现鼠标点击移动矩形: ```python class InteractiveView(QGraphicsView): def mousePressEvent(self, event): item = self.scene().itemAt(self.mapToScene(event.pos()), self.transform()) if isinstance(item, QGraphicsRectItem): item.setPos(100, 100) # 点击后移动矩形位置 super().mousePressEvent(event) # 使用时替换视图类 view = InteractiveView(scene) ``` 此代码重写了视图的鼠标事件,点击矩形会改变其位置[^4]。 #### 五、动画与刷新 通过定时器实现简单动画: ```python from PyQt6.QtCore import QTimer rect = scene.addRect(0, 0, 30, 30) timer = QTimer() timer.timeout.connect(lambda: rect.setPos(rect.x() + 1, rect.y())) timer.start(50) # 每50ms移动1像素 ``` #### 六、注意事项 1. **坐标系**:场景坐标系以中心为原点,视图坐标系以左上角为原点 2. **性能优化**:超过10,000个图形项时建议使用`QGraphicsWidget`或分页加载 3. **事件传递**:优先级顺序为:图形项 > 场景 > 视图
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LaoYuanPython

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值