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 矩形的和高


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM