Qt图形视图框架允许你开发_快速_ _有效的_2D矢量图形场景。场景可以包含_数百万个_项目,每个项目都有自己的特征和行为。通过PyQt使用图形视图,你可以在Python中访问这个高性能的图形层。无论你是将矢量图形视图集成到现有的PyQt应用程序中,还是仅仅想要一个强大的Python矢量图形界面,Qt的图形视图都是你正在寻找的。
图形视图的一些常见用途包括数据可视化、地图应用、二维设计工具、现代数据仪表盘,甚至是二维游戏。
在本教程中,我们将迈出第一步,看看Qt图形视图框架,用一些简单的矢量项目构建一个场景。这将使我们熟悉API和坐标系统,以后我们将用它来构建更复杂的例子。
图形视图框架
图形视图框架由3个主要部分组成:QGraphicsView
、QGraphicsScene
、QGraphicsItem
,每个部分有不同的职责。
该框架可以用模型-视图范式来解释,QGraphicsScene
作为_模型_,QGraphicsView
作为_视图_。每个场景可以有多个视图。 场景中的_QGraphicsItems_可以被看作是模型中的项目,持有视觉数据,场景将其结合起来定义完整的图像。
QGraphicsScene
是将所有东西粘在一起的中心组件。它就像一块_白板_,所有的项目都画在上面(圆形、矩形、线、像素图等)。QGraphicsView
负责渲染一个给定的场景--或其中的一部分,并进行一些转换(缩放、旋转、剪切)--将其显示给用户。视图是一个标准的Qt部件,可以放在任何Qt布局中。
QGraphicsScene
提供了一些开箱即用的重要功能,因此我们可以用它们来开发高级的应用程序,而不必纠结于低级的细节。例如 --
- 碰撞检测,检测一个图形项目与另一个项目的碰撞。
- 项目选择,让我们有能力同时处理多个项目,例如,用户可以选择多个项目,当按下删除键时,有一个函数要求场景给出所有被选择的项目的列表,然后删除它们。
- 物品发现,场景可以告诉我们在一个特定的点或一些定义的区域内有哪些物品(或其中的一部分),例如,如果用户添加的物品与一个禁区相交,程序会检测到它们并给它们另一种颜色(主要是红色)。
- 事件传播,场景接收事件,然后将其传播给物品。
要定义一个QGraphicsScene
,你要定义它的边界或_sceneRect_,它定义了场景的x & y原点和尺寸。如果你不提供_sceneRect_,它将默认为所有子项目的最小边界矩形--随着项目的添加、移动或删除而更新。这很灵活,但效率较低。
场景中的项目是由QGraphicsItem
对象表示的。这些对象是任何二维场景的基本构件,代表将在场景中显示的形状、像素图或SVG图像。每个项目在sceneRect
内都有一个相对位置,并且可以有不同的变换效果(缩放、平移、旋转、剪切)。
最后,QGraphicsView
是场景的渲染器,将场景全部或部分地显示给用户。视图本身可以应用变换(缩放、平移、旋转和剪切)来修改显示,而不影响底层场景。默认情况下,视图会将鼠标和键盘事件转发到场景中,以便于用户交互。这可以通过调用view.setInteractive(False)
来禁用。
一个简单的场景
让我们从创建一个简单的场景开始。下面的代码创建了QGraphicsScene
,定义了一个400 x 200的场景,然后将其显示在QGraphicsView
。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QApplication
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
view = QGraphicsView(scene)
view.show()
app.exec_()
蟒蛇
import sys
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QApplication
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
view = QGraphicsView(scene)
view.show()
app.exec()
如果你运行这个例子,你会看到一个空窗口。
空的图形场景,显示在一个QGraphicsView窗口中。
还不是很刺激 -- 但这是我们的QGraphicsView
,显示我们的_空_场景。
如前所述,QGraphicsView
是一个_widget_。在Qt中,任何没有父级的widget都会显示为窗口。这就是为什么我们的QGraphicsView
在桌面上显示为一个窗口。
添加项目
让我们开始在场景中添加一些项目。有许多内置的_图形项_,你可以自定义并添加到你的场景中。 在下面的例子中,我们使用QGraphicsRectItem
,它可以画一个矩形。我们创建了这个项目,输入了它的尺寸,然后在把它添加到场景中之前设置了它的位置笔和画笔。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QApplication
from PyQt5.QtGui import QBrush, QPen
from PyQt5.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.cyan)
pen.setWidth(10)
rect.setPen(pen)
scene.addItem(rect)
view = QGraphicsView(scene)
view.show()
app.exec_()
蟒蛇
import sys
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QApplication
from PyQt6.QtGui import QBrush, QPen
from PyQt6.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.GlobalColor.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.GlobalColor.cyan)
pen.setWidth(10)
rect.setPen(pen)
scene.addItem(rect)
view = QGraphicsView(scene)
view.show()
app.exec()
运行上述程序,你会在场景中看到一个单一的、颜色相当难看的矩形。
场景中的一个矩形
添加更多的项目只是简单地创建对象,自定义它们,然后将它们添加到场景中。在下面的例子中,我们使用QGraphicsEllipseItem
,添加了一个圆--一个圆只是一个高度和宽度相等的椭圆。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QGraphicsEllipseItem, QApplication
from PyQt5.QtGui import QBrush, QPen
from PyQt5.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
scene.addItem(ellipse)
scene.addItem(rect)
view = QGraphicsView(scene)
view.show()
app.exec_()
蟒蛇
import sys
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QGraphicsEllipseItem, QApplication
from PyQt6.QtGui import QBrush, QPen
from PyQt6.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.GlobalColor.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.GlobalColor.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.GlobalColor.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.GlobalColor.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
scene.addItem(ellipse)
scene.addItem(rect)
view = QGraphicsView(scene)
view.show()
app.exec()
上述代码将得到以下结果。
一个有两个项目的场景
你添加项目的顺序会影响场景中的堆叠顺序--后来添加的项目总是出现_在_先添加的项目_之上_。然而,如果你需要更多的控制,你可以使用.setZValue
来_设置_堆叠顺序。
python
ellipse.setZValue(500)
rect.setZValue(200)
现在,圆(椭圆)出现在矩形的上方。
使用Z值来排列场景中的项目
试着实验一下设置两个项目的Z值--你可以_在_项目进入场景_之前_或_之后_设置它,并且可以随时改变它。
Z在这里指的是Z坐标。X和Y坐标分别是场景中的水平和垂直位置。Z坐标决定了物品在场景中前后的相对位置--从屏幕中 "出来 "朝向观看者。
还有方便的方法.stackBefore()
和.stackAfter()
,这些方法允许你在场景中的另一个项目后面或前面堆叠你的QGraphicsItem
。
蟒蛇
ellipse.stackAfter(rect)
使项目可移动
我们的两个QGraphicsItem
对象目前在我们放置它们的地方是固定的,但它们不一定是固定的。如前所述,Qt的图形视图框架允许项目响应用户的输入,例如允许它们在场景中随意拖动。像这样的简单功能实际上已经内置了,你只需要在每个QGraphicsItem
。要做到这一点,我们需要在项目上设置标志QGraphicsItem.GraphicsItemFlags.ItemIsMoveable
。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QGraphicsRectItem, QGraphicsEllipseItem, QApplication
from PyQt5.QtGui import QBrush, QPen
from PyQt5.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
scene.addItem(ellipse)
scene.addItem(rect)
ellipse.setFlag(QGraphicsItem.ItemIsMovable)
view = QGraphicsView(scene)
view.show()
app.exec_()
蟒蛇
import sys
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QGraphicsRectItem, QGraphicsEllipseItem, QApplication
from PyQt6.QtGui import QBrush, QPen
from PyQt6.QtCore import Qt
app = QApplication(sys.argv)
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
# Set the origin (position) of the rectangle in the scene.
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.GlobalColor.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.GlobalColor.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.GlobalColor.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.GlobalColor.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
scene.addItem(ellipse)
scene.addItem(rect)
ellipse.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
view = QGraphicsView(scene)
view.show()
app.exec()
在上面的例子中,我们只在_椭圆_上设置了ItemIsMovable
。你可以在场景中拖动椭圆--包括在矩形的后面--但矩形本身将被锁定在原地。实验一下添加更多的项目和配置可移动状态。
如果你想让一个项目是_可选择的_,你可以通过设置ItemIsSelectable
标志来实现,例如这里用.setFlags()
来同时设置多个标志。
python
ellipse.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)
如果你点击椭圆,你现在会看到它被一条虚线包围,表示它被选中了。我们将在后面的教程中更详细地研究如何使用项目选择。
场景中的一个被选中的项目,用虚线突出显示
创建对象的另一种方法。
到目前为止,我们一直是通过创建对象,_然后_把它们添加到场景中来创建项目。但是你也可以通过调用场景本身的一个辅助方法来直接_在_场景中创建一个对象,例如:scene.addEllipse()
。这将_创建对象_并_返回_它,所以你可以像以前一样修改它。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QApplication
from PyQt5.QtGui import QBrush, QPen
from PyQt5.QtCore import Qt
app = QApplication(sys.argv)
scene = QGraphicsScene(0, 0, 400, 200)
rect = scene.addRect(0, 0, 200, 50)
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.cyan)
pen.setWidth(10)
rect.setPen(pen)
view = QGraphicsView(scene)
view.show()
app.exec_()
蟒蛇
import sys
from PyQt6.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsRectItem, QApplication
from PyQt6.QtGui import QBrush, QPen
from PyQt6.QtCore import Qt
app = QApplication(sys.argv)
scene = QGraphicsScene(0, 0, 400, 200)
rect = scene.addRect(0, 0, 200, 50)
rect.setPos(50, 20)
# Define the brush (fill).
brush = QBrush(Qt.GlobalColor.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.GlobalColor.cyan)
pen.setWidth(10)
rect.setPen(pen)
view = QGraphicsView(scene)
view.show()
app.exec()
在你的代码中,请随意使用你认为最舒服的形式。
你只能对内置的QGraphicsItem
对象类型使用这种方法。
建立一个更复杂的场景
到目前为止,我们已经使用基本的QGraphicsRectItem
和QGraphicsEllipseItem
形状建立了一个简单的场景。现在让我们使用一些其他的QGraphicsItem
对象来构建一个更复杂的场景,包括线条、文本和QPixmap
(图像)。
- PyQt5
- PyQt5
蟒蛇
from PyQt5.QtCore import QPointF, Qt
from PyQt5.QtWidgets import QGraphicsRectItem, QGraphicsScene, QGraphicsView, QApplication
from PyQt5.QtGui import QBrush, QPainter, QPen, QPixmap, QPolygonF
import sys
app = QApplication(sys.argv)
scene = QGraphicsScene(0, 0, 400, 200)
rectitem = QGraphicsRectItem(0, 0, 360, 20)
rectitem.setPos(20, 20)
rectitem.setBrush(QBrush(Qt.red))
rectitem.setPen(QPen(Qt.cyan))
scene.addItem(rectitem)
textitem = scene.addText("QGraphics is fun!")
textitem.setPos(100, 100)
scene.addPolygon(
QPolygonF(
[
QPointF(30, 60),
QPointF(270, 40),
QPointF(400, 200),
QPointF(20, 150),
]),
QPen(Qt.darkGreen),
)
pixmap = QPixmap("cat.jpg")
pixmapitem = scene.addPixmap(pixmap)
pixmapitem.setPos(250, 70)
view = QGraphicsView(scene)
view.setRenderHint(QPainter.Antialiasing)
view.show()
app.exec_()
蟒蛇
from PyQt6.QtCore import QPointF, Qt
from PyQt6.QtWidgets import QGraphicsRectItem, QGraphicsScene, QGraphicsView, QApplication
from PyQt6.QtGui import QBrush, QPainter, QPen, QPixmap, QPolygonF
import sys
app = QApplication(sys.argv)
scene = QGraphicsScene(0, 0, 400, 200)
rectitem = QGraphicsRectItem(0, 0, 360, 20)
rectitem.setPos(20, 20)
rectitem.setBrush(QBrush(Qt.GlobalColor.red))
rectitem.setPen(QPen(Qt.GlobalColor.cyan))
scene.addItem(rectitem)
textitem = scene.addText("QGraphics is fun!")
textitem.setPos(100, 100)
scene.addPolygon(
QPolygonF(
[
QPointF(30, 60),
QPointF(270, 40),
QPointF(400, 200),
QPointF(20, 150),
]),
QPen(Qt.GlobalColor.darkGreen),
)
pixmap = QPixmap("cat.jpg")
pixmapitem = scene.addPixmap(pixmap)
pixmapitem.setPos(250, 70)
view = QGraphicsView(scene)
view.setRenderHint(QPainter.RenderHint.Antialiasing)
view.show()
app.exec()
如果你运行上面的例子,你会看到下面的场景。
场景中有多个项目,包括一个矩形、多边形、文本和一个像素图。
让我们看一下代码中有趣的部分。
多边形是用一系列的QPointF
对象来定义的,这些对象给出了相对于_项目_位置的坐标。因此,例如,如果你创建了一个点在30,20的多边形对象,然后移动这个多边形对象的X和Y坐标50,40,那么这个点将在场景中显示为80,60。
项目内的点总是相对于项目本身的,而项目坐标总是相对于场景的--或者项目的父对象,如果它有一个的话。我们将在下一个教程中仔细研究图形视图的坐标系统。
为了将图像添加到场景中,我们可以使用QPixmap()
从一个文件中打开它。这将创建一个QPixmap
对象,然后再使用scene.addPixmap(pixmap)
添加到场景中。这将返回一个QGraphicsPixmapItem
,它是像素图的QGraphicsItem
类型--一个处理在场景中显示像素图的包装器。你可以使用这个对象来对场景中的项目进行任何改变。
多层的对象会让人感到困惑,所以选择合理的变量名是很重要的,它可以明确区分,例如,_像素图_本身和包含它的_像素图项_之间的区别。
最后,我们在视图上设置标志RenderHint,Antialiasing
,以_平滑_对角线的边缘。你几乎_总是_想在你的视图上启用这个功能,否则任何旋转的物体看起来都会非常难看。下面是我们没有启用抗锯齿的场景,你可以看到多边形上锯齿状的线条。
禁用抗锯齿的场景。
然而,抗锯齿对性能有(小的)影响,所以如果你正在构建有数百万个旋转项目的场景,在某些情况下,关闭它可能是有意义的。
将图形视图添加到Qt布局中
QGraphicsView
是从QWidget
子类化的,这意味着它可以像其他widget一样被放在布局中。在下面的例子中,我们将视图添加到一个简单的界面中,按钮对视图执行一个基本的效果--提高和降低所选项目的ZValue。这样做的效果是允许我们将项目移到其他对象的前面和后面。
下面给出了完整的代码。
- PyQt5
- PyQt6
蟒蛇
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QBrush, QPainter, QPen
from PyQt5.QtWidgets import (
QApplication,
QGraphicsEllipseItem,
QGraphicsItem,
QGraphicsRectItem,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QPushButton,
QSlider,
QVBoxLayout,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
self.scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
rect.setPos(50, 20)
brush = QBrush(Qt.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
self.scene.addItem(ellipse)
self.scene.addItem(rect)
# Set all items as moveable and selectable.
for item in self.scene.items():
item.setFlag(QGraphicsItem.ItemIsMovable)
item.setFlag(QGraphicsItem.ItemIsSelectable)
# Define our layout.
vbox = QVBoxLayout()
up = QPushButton("Up")
up.clicked.connect(self.up)
vbox.addWidget(up)
down = QPushButton("Down")
down.clicked.connect(self.down)
vbox.addWidget(down)
rotate = QSlider()
rotate.setRange(0, 360)
rotate.valueChanged.connect(self.rotate)
vbox.addWidget(rotate)
view = QGraphicsView(self.scene)
view.setRenderHint(QPainter.Antialiasing)
hbox = QHBoxLayout(self)
hbox.addLayout(vbox)
hbox.addWidget(view)
self.setLayout(hbox)
def up(self):
""" Iterate all selected items in the view, moving them forward. """
items = self.scene.selectedItems()
for item in items:
z = item.zValue()
item.setZValue(z + 1)
def down(self):
""" Iterate all selected items in the view, moving them backward. """
items = self.scene.selectedItems()
for item in items:
z = item.zValue()
item.setZValue(z - 1)
def rotate(self, value):
""" Rotate the object by the received number of degrees """
items = self.scene.selectedItems()
for item in items:
item.setRotation(value)
app = QApplication(sys.argv)
w = Window()
w.show()
app.exec()
蟒蛇
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QBrush, QPainter, QPen
from PyQt6.QtWidgets import (
QApplication,
QGraphicsEllipseItem,
QGraphicsItem,
QGraphicsRectItem,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QPushButton,
QSlider,
QVBoxLayout,
QWidget,
)
class Window(QWidget):
def __init__(self):
super().__init__()
# Defining a scene rect of 400x200, with it's origin at 0,0.
# If we don't set this on creation, we can set it later with .setSceneRect
self.scene = QGraphicsScene(0, 0, 400, 200)
# Draw a rectangle item, setting the dimensions.
rect = QGraphicsRectItem(0, 0, 200, 50)
rect.setPos(50, 20)
brush = QBrush(Qt.GlobalColor.red)
rect.setBrush(brush)
# Define the pen (line)
pen = QPen(Qt.GlobalColor.cyan)
pen.setWidth(10)
rect.setPen(pen)
ellipse = QGraphicsEllipseItem(0, 0, 100, 100)
ellipse.setPos(75, 30)
brush = QBrush(Qt.GlobalColor.blue)
ellipse.setBrush(brush)
pen = QPen(Qt.GlobalColor.green)
pen.setWidth(5)
ellipse.setPen(pen)
# Add the items to the scene. Items are stacked in the order they are added.
self.scene.addItem(ellipse)
self.scene.addItem(rect)
# Set all items as moveable and selectable.
for item in self.scene.items():
item.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
item.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
# Define our layout.
vbox = QVBoxLayout()
up = QPushButton("Up")
up.clicked.connect(self.up)
vbox.addWidget(up)
down = QPushButton("Down")
down.clicked.connect(self.down)
vbox.addWidget(down)
rotate = QSlider()
rotate.setRange(0, 360)
rotate.valueChanged.connect(self.rotate)
vbox.addWidget(rotate)
view = QGraphicsView(self.scene)
view.setRenderHint(QPainter.RenderHint.Antialiasing)
hbox = QHBoxLayout(self)
hbox.addLayout(vbox)
hbox.addWidget(view)
self.setLayout(hbox)
def up(self):
""" Iterate all selected items in the view, moving them forward. """
items = self.scene.selectedItems()
for item in items:
z = item.zValue()
item.setZValue(z + 1)
def down(self):
""" Iterate all selected items in the view, moving them backward. """
items = self.scene.selectedItems()
for item in items:
z = item.zValue()
item.setZValue(z - 1)
def rotate(self, value):
""" Rotate the object by the received number of degrees. """
items = self.scene.selectedItems()
for item in items:
item.setRotation(value)
app = QApplication(sys.argv)
w = Window()
w.show()
app.exec()
如果你运行它,你会得到一个如下所示的窗口。通过在图形视图中选择一个项目,然后点击 "向上 "或 "向下 "按钮,你可以在场景中上下移动项目--在彼此的后面和前面。这些项目都是可移动的,所以你也可以拖动它们。点击滑块将使当前选定的项目旋转设定的度数。
一个带有一些自定义控件的图形场景
提升和降低是由我们的自定义方法up
和down
来处理的,它的工作原理是在场景中迭代_当前选定的_项目--使用scene.selectedItems()
检索,然后获得项目的z值,并分别增加或减少它。
蟒蛇
def up(self):
""" Iterate all selected items in the view, moving them forward. """
items = self.scene.selectedItems()
for item in items:
z = item.zValue()
item.setZValue(z + 1)
而旋转是使用item.setRotation
方法处理的。这个方法从QSlider
接收当前的角度,并再次将其应用于场景中任何当前选定的项目。
蟒蛇
def rotate(self, value):
""" Rotate the object by the received number of degrees. """
items = self.scene.selectedItems()
for item in items:
item.setRotation(value)
看看QGraphicsItem的文档,了解一些你可以用部件控制的其他属性,并尝试扩展接口以允许你动态地改变它们。
希望这个关于Qt图形视图框架的快速介绍能给你一些关于你能用它做什么的想法。在接下来的教程中,我们将看看如何在项目上处理事件和用户交互,以及如何为你自己的场景创建自定义和复合项目。
更多内容请看完整的PyQt5教程。