第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!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章