pyqt5--QGraphicsView
在Qt界面库中,对于图形的绘制,在前面介绍了一种使用QPainter实现普通二维图形的绘制方法,该方法在paintEvent事件里编写绘图程序,其本质绘制的图形是位图,这种方法更适合于绘制复杂度不高的固定图形,并且不能实现图项的选择、编辑、拖放、修改等交互功能。
对于需要绘制大量的、需要交互的图形,可使用Graphics View绘图架构,它是一种基于图形项(Graphics Item)的模型/视图模式,这种方式可以在一个场景中可绘制大量图元项,且每个图元项都是可选择、可交互的。
在Graphics View绘图架构中,主要涉及到下面三个类的使用:
1. 场景类(QGraphicsScene):该类提供绘图场景(Scene),场景是不可见的,是一个抽象的管理图形项的容器,可向场景中添加图形项,获取场景中的某个图形项等;
2. 视图类(QGraphicsView):该类提供绘图的视图(View)组件,用于显示场景中的内容。可以为一个场景设置几个视图,用于对同一个数据集提供不同的观察方式;
3. 图形项类(QGraphicsItem):该类提供了一些基本的图形元件,也可在此基础上自定义图形项,它支持各种事件的响应,如鼠标事件、键盘事件、拖放事件等,以实现图形的交互功能
在Graphics View绘图架构中涉及到了3个坐标系,即场景坐标、视图坐标及图形项坐标。其中,场景坐标类似于QPainter的逻辑坐标,一般以场景的中心为原点;视图坐标是窗口界面的物理坐标,其左上角为原点坐标;图形项坐标是局部逻辑坐标,通常以图件的中心为原点
坐标实例
import sys from PyQt5.QtWidgets import QApplication,QGraphicsScene,QGraphicsView,QGraphicsRectItem,QMainWindow,QLabel,QGraphicsItem,QGraphicsEllipseItem from PyQt5.QtCore import Qt,pyqtSignal,QPoint,QRectF class QMyGraphicsView(QGraphicsView): sigMouseMovePoint=pyqtSignal(QPoint) #自定义信号sigMouseMovePoint,当鼠标移动时,在mouseMoveEvent事件中,将当前的鼠标位置发送出去 #QPoint--传递的是view坐标 def __init__(self,parent=None): super(QMyGraphicsView,self).__init__(parent) def mouseMoveEvent(self, evt): pt=evt.pos() #获取鼠标坐标--view坐标 self.sigMouseMovePoint.emit(pt) #发送鼠标位置 QGraphicsView.mouseMoveEvent(self, evt) class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.resize(600,400) self.view=QMyGraphicsView() #创建视图窗口 self.setCentralWidget(self.view) # 设置中央控件 self.statusbar=self.statusBar() #添加状态栏 self.labviewcorrd=QLabel('view坐标:') self.labviewcorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labviewcorrd) self.labscenecorrd=QLabel('scene坐标:') self.labscenecorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labscenecorrd) self.labitemcorrd = QLabel('item坐标:') self.labitemcorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labitemcorrd) rect=QRectF(-200,-100,400,200) self.scene=QGraphicsScene(rect) #创建场景 #参数:场景区域 #场景坐标原点默认在场景中心---场景中心位于界面中心 self.view.setScene(self.scene) #给视图窗口设置场景 item1=QGraphicsRectItem(rect) #创建矩形---以场景为坐标 item1.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable|QGraphicsItem.ItemIsMovable) #给图元设置标志 #QGraphicsItem.ItemIsSelectable---可选择 #QGraphicsItem.ItemIsFocusable---可设置焦点 #QGraphicsItem.ItemIsMovable---可移动 #QGraphicsItem.ItemIsPanel--- self.scene.addItem(item1) #给场景添加图元 for pos,color in zip([rect.left(),0,rect.right()],[Qt.red,Qt.yellow,Qt.blue]): item=QGraphicsEllipseItem(-50,-50,100,100) #创建椭圆--场景坐标 #参数1 参数2 矩形左上角坐标 #参数3 参数4 矩形的宽和高 item.setPos(pos,0) #给图元设置在场景中的坐标(移动图元)--图元中心坐标 item.setBrush(color) #设置画刷 item.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable|QGraphicsItem.ItemIsMovable) self.scene.addItem(item) self.scene.clearSelection() #【清除选择】 self.view.sigMouseMovePoint.connect(self.slotMouseMovePoint) def slotMouseMovePoint(self,pt): self.labviewcorrd.setText('view坐标:{},{}'.format(pt.x(),pt.y())) ptscene=self.view.mapToScene(pt) #把view坐标转换为场景坐标 self.labscenecorrd.setText('scene坐标:{:.0f},{:.0f}'.format(ptscene.x(),ptscene.y())) item=self.scene.itemAt(ptscene,self.view.transform()) #在场景某点寻找图元--最上面的图元 #返回值:图元地址 #参数1 场景点坐标 #参数2 ???? if item != None: ptitem=item.mapFromScene(ptscene) #把场景坐标转换为图元坐标 self.labitemcorrd.setText('item坐标:{:.0f},{:.0f}'.format(ptitem.x(),ptitem.y())) if __name__ == "__main__": app = QApplication(sys.argv) ex = MainWindow() ex.show() sys.exit(app.exec_())
import sys
from PyQt5.QtWidgets import QWidget, QApplication,QGraphicsScene,QGraphicsView
import time
class Example(QWidget):
def __init__(self):
super().__init__()
self.resize(500,400)
scene=QGraphicsScene(self) #创建场景
self.t=scene.addText("Hello, world!") #在场景中添加文本
view=QGraphicsView(scene,self) #创建视图窗口
view.move(10,10)
view.show() #显示
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
添加文本图元
font=QFont("华文琥珀",20,QFont.Bold)
t=scene.addText("Hello, world!",font) #在场景中添加文本图元
#参数1 文本
#参数2 字体
添加矩形
pen = QPen() pen.setColor(Qt.blue) pen.setWidth(3) brush = QBrush(Qt.SolidPattern) brush.setColor(Qt.yellow) rect = QRectF(130,130,100,150) juxin=scene.addRect(30,30,100,100,pen,brush) #添加矩形图元--方式一 #参数1--参数4 坐标和宽高---以View为坐标系 #参数5 画笔 #参数6 画刷 juxin = scene.addRect(rect, pen, brush) # 添加矩形图元--方式二
rect = QRectF(0,0,100,100) item1 = QGraphicsRectItem(rect) # 创建矩形---以场景为坐标 scene.addItem(item1)
添加线段
pen = QPen() pen.setColor(Qt.blue) pen.setWidth(3) line=scene.addLine(0,0,50,50,pen) #添加直线--方式一 lf=QLineF(50,50,0,50) line = scene.addLine(lf, pen) #添加直线--方式二
添加椭圆
item = QGraphicsEllipseItem(10, 10, 100, 100) # 创建椭圆--场景坐标 # 参数1 参数2 矩形左上角坐标 # 参数3 参数4 矩形的宽和高 scene.addItem(item)
item=scene.addEllipse(10, 10, 100, 100,pen,brush)
rect=QRectF(10, 10, 100, 100)
item=scene.addEllipse(rect,pen,brush)
图元的操作(缩放,平移,旋转)
想要旋转,平移,缩放窗口中的图元,一般有两种思路:
1. 操作View,概念类似于旋转摄像头,从而获取对场景Scene的不同观察结果,这样操作的好处是,场景中的图元本质上没有发生任何的变化,仅仅改变了View的计算矩阵,效率非常高,并且,如果该Scene被多个View绑定观察,对单独一个view的操作,将不会影响到别的view的观察结果
2.操作Scene中所有的图元Item或者直接操作单个图元Item,概念类似于真实改变了场景中的各个物体的摆放方式,该方法使用的场合位:当一个场景,被多个view观察的时候,场景中的某一个变化操作,需要被这多个view同时观察到
下面是操作图元的方法
1. 图元的缩放:
rect=QRectF(100, 100, 200, 100) item=scene.addEllipse(rect,pen,brush) item.setScale(0.5) #对图元进行缩放 #参数为图元大小的缩放比 #需要注意的是,该方法的缩放基准是固定的,也就是说,如果连续两次调用该方法,但是参数的数字一样的话,第二次的调用将不会改变图元的大小 print(item.scale()) #返回图元的缩放比
2.图元的平移
item=scene.addRect(200,200,200,100,pen,brush) item.setPos(100,50) #移动图元--方式一 #参数 移动的偏移量 #其传参的x与y坐标值,属于场景Scene的坐标,如果调用的时候,坐标来源于view的鼠标点击事件的坐标,需要调用mapToScene()将view坐标值转换到场景坐标 item.moveBy(100,50) #移动图元--方式二
3.图元的旋转
import sys from PyQt5.QtWidgets import QWidget, QApplication,QGraphicsScene,QGraphicsView,QGraphicsRectItem,QGraphicsEllipseItem,QGraphicsItem,QPushButton from PyQt5.QtGui import QPen,QBrush from PyQt5.QtCore import Qt,QRectF,QLineF class Example(QWidget): def __init__(self): super().__init__() self.resize(500,400) scene=QGraphicsScene() #创建场景 scene.setSceneRect(0,0,600,500) #设置场景的坐标原点和宽高 pen = QPen() pen.setColor(Qt.blue) pen.setWidth(3) brush=QBrush(Qt.yellow) item1=scene.addRect(0,0,250,25,pen,brush) item=scene.addRect(100,100,200,100,pen,brush) item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) item.setPos(-100, -100) item.setTransformOriginPoint(0,0) #设置旋转中心----???不按这点旋转啊 #默认 图元的左上角 #该方法传参的坐标值为图元自身的坐标系 item.setRotation(30) #旋转图元 #参数 角度 #正数 逆时针 #设置的值的基准也是不变的,也就是说,连续两次调用该方法,都传入相同的参数值,图元只会旋转一次 print(item.rotation()) #返回旋转角度 view=QGraphicsView(scene,self) #创建视图窗口 view.resize(500,400) view.show() #显示 if __name__ == "__main__": app = QApplication(sys.argv) ex = Example() ex.show() sys.exit(app.exec_())
天子骄龙
item=QGraphicsEllipseItem(-50,-50,100,100) #创建椭圆--场景坐标
#参数1 参数2 矩形左上角坐标
#参数3 参数4 矩形的宽和高