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 矩形的和高
posted @ 2019-04-01 09:37  天子骄龙  阅读(10063)  评论(1编辑  收藏  举报