1. 程式人生 > >Qt學習筆記:畫一條帶箭頭的線

Qt學習筆記:畫一條帶箭頭的線

方法1:常規實現

帶箭頭的線,在很多地方都會用到,以致於一開始我認為Qt會提供這樣一個類。。。沒想到的是Qt不僅沒有提供相關的類,自己實現的時候還頗為複雜。。

其實我比較不理解。。為什麼Qt不提供一個帶箭頭的線的類呢。。為什麼為什麼呢?這個應該不少人會用到吧。。。

廢話不多說,下面開始:

帶箭頭的線,簡單來講就是一條線加上一個三角形,我們可以通過自定義一個繼承自QGraphicsLineItem的類,並重寫他的paint()方法來實現:

我們先畫一條沒有箭頭的線:

class MyWidget(QGraphicsView):
    def __init__(self):
        super(MyWidget, self).__init__()
        self.setFixedSize(300
, 300) self.setSceneRect(0, 0, 250, 250) self.scene = QGraphicsScene() self.setScene(self.scene) self.scene.addItem(MyArrow()) class MyArrow(QGraphicsLineItem): def __init__(self): super(MyArrow, self).__init__() self.source = QPointF(0, 250) self.dest = QPointF(120
, 120) self.line = QLineF(self.source, self.dest) self.line.setLength(self.line.length() - 20) def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None): # setPen pen = QPen() pen.setWidth(5) pen.setJoinStyle(Qt.MiterJoin) #讓箭頭變尖 QPainter.setPen(pen) # draw line
QPainter.drawLine(self.line) if __name__ == '__main__': import sys app = QApplication(sys.argv) w = MyWidget() w.show() sys.exit(app.exec_())

效果如圖:

這裡寫圖片描述

然後我們再在這條線的基礎上畫上箭頭:

首先利用QLineF().unitVector()函式得到它的單位向量,並將它移到原線的終點位置,注意這裡的偏移量。

    v = self.line.unitVector()
    v.setLength(20) # 改變單位向量的大小,實際就是改變箭頭長度
    v.translate(QPointF(self.line.dx(), self.line.dy()))

這時候我們就得到這樣一條線:

這裡寫圖片描述

然後我們利用normalVector()函式得到他的法向量,然後再利用normalVector()得到法向量的反方向的向量。

        n = v.normalVector() # 法向量
        n.setLength(n.length() * 0.5) # 這裡設定箭頭的寬度
        n2 = n.normalVector().normalVector() # 兩次法向量運算以後,就得到一個反向的法向量
這裡寫圖片描述

然後我們取得 3 個向量的終點 為箭頭的三個端點,並以這三點為頂點畫出三角形

        p1 = v.p2()
        p2 = n.p2()
        p3 = n2.p2()        
        QPainter.drawPolygon(p1, p2, p3)
這裡寫圖片描述

至此,箭頭就算完成了!
如果你喜歡,你還可以填充箭頭

        brush = QBrush()
        brush.setColor(Qt.black)
        brush.setStyle(Qt.SolidPattern)
        QPainter.setBrush(brush)

最後完成如下:

這裡寫圖片描述這裡寫圖片描述

方法2:利用QPainterPath實現

QPainterPath其實是一個容器,他可以包含一個或者多個不同的繪畫步驟,通過這些步驟組成較為複雜的圖案,然後使用QPainter.drawPath()將這些圖案一次性畫出來。

實現的方式和普通方法的區別在於:

普通方法分兩步畫出圖形,先畫線,再畫箭頭

        QPainter.drawLine(self.line)
        QPainter.drawPolygon(p1, p2, p3)

而利用QPainterPath,則是先將整個繪製過程設定好,然後一次性畫出整個path

        arrow = QPolygonF([p1, p2, p3, p1])
        path = QPainterPath()
        path.moveTo(self.source) # 移動到線原點
        path.lineTo(self.dest) # 新增線的路徑
        path.addPolygon(arrow) # 新增箭頭路徑

        QPainter.drawPath(path) # 畫出整個路徑

總結:

  1. 箭頭相當於是這條線的額外部分,如果你對線的端點很敏感的話,要注意實際的長度 = 線原長 + 箭頭的長度。
  2. 三角形算是最簡單的圖形了,並沒有完全發揮QPainterPath的威力,事實上,你可以畫朵花兒在線上。^0^

最後附上完整程式碼:

# coding:utf-8

from PyQt4.QtCore import *
from PyQt4.QtGui import *


class MyWidget(QGraphicsView):
    def __init__(self):
        super(MyWidget, self).__init__()
        self.setFixedSize(300, 300)
        self.setSceneRect(0, 0, 250, 250)
        self.scene = QGraphicsScene()
        self.setScene(self.scene)
        self.scene.addItem(MyArrow())


class MyArrow(QGraphicsLineItem):
    def __init__(self):
        super(MyArrow, self).__init__()
        self.source = QPointF(0, 250)
        self.dest = QPointF(120, 120)
        self.line = QLineF(self.source, self.dest)
        self.line.setLength(self.line.length() - 20)

    def paint(self, QPainter, QStyleOptionGraphicsItem, QWidget_widget=None):
        # setPen
        pen = QPen()
        pen.setWidth(5)
        pen.setJoinStyle(Qt.MiterJoin)
        QPainter.setPen(pen)

        # setBrush
        brush = QBrush()
        brush.setColor(Qt.black)
        brush.setStyle(Qt.SolidPattern)
        QPainter.setBrush(brush)

        v = self.line.unitVector()
        v.setLength(20)
        v.translate(QPointF(self.line.dx(), self.line.dy()))

        n = v.normalVector()
        n.setLength(n.length() * 0.5)
        n2 = n.normalVector().normalVector()

        p1 = v.p2()
        p2 = n.p2()
        p3 = n2.p2()

        # 方法1
        QPainter.drawLine(self.line)
        QPainter.drawPolygon(p1, p2, p3)

        # 方法2
        # arrow = QPolygonF([p1, p2, p3, p1])
        # path = QPainterPath()
        # path.moveTo(self.source)
        # path.lineTo(self.dest)
        # path.addPolygon(arrow)
        # QPainter.drawPath(path)


if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    w = MyWidget()
    w.show()
    sys.exit(app.exec_())

相關推薦

Qt學習筆記箭頭

方法1:常規實現 帶箭頭的線,在很多地方都會用到,以致於一開始我認為Qt會提供這樣一個類。。。沒想到的是Qt不僅沒有提供相關的類,自己實現的時候還頗為複雜。。 其實我比較不理解。。為什麼Qt不提供一個帶箭頭的線的類呢。。為什麼為什麼呢?這個應該不少人會用到吧

【unity實用技能】Unity箭頭

無提供函數方便使用 private void DrawArrow(Vector2 from, Vector2 to, Color color) { Handles.BeginGUI(); Handles.color = color; Handle

effectiveJava學習筆記方法()

檢查引數的有效性 1、一般在方法執行之前先檢查引數的有效性,如果引數值無效,那麼很快它就會失敗,並且清楚的丟擲合適的異常。 如果這個方法沒有檢查引數的異常,那麼可能在方法處理中出現令人費解的異常。更糟糕的有可能是,方法可以正常返回,但是卻使得某個物件處於被破壞的狀態. 2、對於公有方法,

Qt學習筆記清除用QAxObject建立的Office程序

環境 系統:Windows10 64位 家庭中文版 Qt版本:5.6.0 msvc2013 32位 編譯器:Visual Studio 2013 專業版 目的 在Qt中,當程式非正常關閉時,用QAxObject建立的Office程序不會隨著程式的關閉而關閉,導致程序殘留。我們需要

Qt學習筆記把QtQuick作為控制元件嵌入到QtWidgets

環境 系統:Windows10 64位 家庭中文版 Qt版本:5.6.0 msvc2013 64位 編譯器:Visual Studio 2013 專業版 目的 把用QML實現的介面嵌入到QtWidget,同時實現對QML屬性的設定。 步驟 1.把要實現的QML視窗設計

Qt學習筆記QLabel同時顯示圖片和文字

環境 系統:Windows10 64位 家庭中文版 Qt版本:5.6.0 msvc2013 64位 編譯器:Visual Studio 2013 專業版 前言 QLabel是Qt自帶的一個顯示用控制元件,可以用來顯示圖片和文字。其使用也非常方便:用setPixmap(cons

QT學習筆記關於QT下配置OpenCV3.4.0後出現 error: undefined reference to 'cv::xxx'的問題及解決方案

按照網上的辦法,在QT中pro檔案末尾新增以下程式碼來引入OpenCV的庫和標頭檔案: INCLUDEPATH += D:\OpenCV3.4\opencv\build_mingw\install\x64\mingw\include LIBS += D:\Ope

《跟老齊學Python輕鬆入門》學習筆記基礎物件型別

第1章 基本物件型別 浮點數的所有運算都要注意 1.1 數和四則運算 1.python可以自動處理大整數問題,不必擔心溢位 2.單精度浮點數(4個位元組)在計算機內部儲存方式: 1位為符號位(0為正,1為負),8位用作整數,最後的23位表示有效數字 3.每個物件在記憶

Qt學習筆記Qt 事件機制

一、Qt中的事件處理 1. 在Qt中,事件被封裝成一個個物件,所有的事件均繼承自抽象類QEvent. 事件處理的核心包括事件①產生、②分發、③接受和處理。 事件的產生: 誰來產生事件? 最容易想到的是我們的輸入裝置,比如鍵盤、滑鼠產生的keyPressEvent,keyR

Qt學習筆記2018年8月記錄

1. Qt 設定背景圖片注意事項: 使用stylesheet設定背景圖片還是有一些要注意的,如果是在mainwindow和dialog中, 直接右鍵change style sheet在add resource中選擇background-image或者border-image,

QT5.11.1結合VS2017學習筆記)環境的配置及HelloWorld的實現

前言:       最近開始學習QT,由於習慣了使用VS而網上的教程大多都是基於QTCreator的,很少有基於VS的。為此,本人決定將自己學習的過程記錄下來。水平有限,有不對的地方,歡迎大家批評指正! 工具及系統:VS2017,Qt5.11.1 一、環境配置 1、安

Qt學習筆記無邊框窗體的移動

類似360安全衛士介面, 滑鼠只能夠在綠色的位置進行點選和移動,這就是採用Qt實現的無邊框窗體的移動。 其實實現無邊框窗體的移動主要是靠以下三個函式: void mousePres

Hadoop學習筆記)WordCount執行

前言:本文是在hadoop已經配置好的情況下 WordCount是hadoop下的HelloWorld程式,是初學者必須要會的。下面是用eclipse進行開發 一、工程與MapReduce程式碼 新建工程,建立WordCount class

Qt學習筆記QDir

前言 接觸過DOS系統的同學就知道,dir命令就是瀏覽當前目錄下的所有檔案及資料夾,和linux下面的ls命令類似。 顧名思義,QDir類就是用來訪問系統目錄結構的一個類。 關於QDir類的具體用法,官方文件講得非常清楚,這裡就不詳細介紹,本

Effective Java學習筆記 第57只針對異常的情況才使用異常

摘要: 異常應該只用於異常的情況下,它們永遠不應該用於正常的控制流。 設計良好的API不應該強迫它的客戶端為了正常的控制流而使用異常。 如果物件有“狀態相關的方法”。可以使用如下的兩種方式來避免呼叫該方法時,丟擲異常。 狀態測試方法 使用方法來判斷

Qt學習筆記打包exe程式

在Qt Creator通過release能夠生成exe檔案,但是單獨執行會缺失很多dll檔案,當然你可以按照錯誤提示一個一個的將這些dll檔案從qt安裝目錄中複製黏貼過去,但是這樣做很麻煩,而且一不小心容易出錯。 windeployqt 實際上Qt提

基本設計模式學習筆記)常見的七種面向物件設計原則

0.概述      面向物件設計原則為支援可維護性複用而誕生,這些原則蘊含在很多設計模式中,他們是從許多設計方案中總結出來的指導性原則1.單一原則     一個類只負責一個功能領域中的相應職責,或者說:就一個類而言,應該只有一個引起它變化的原因。個人總結:將不同職責的方法放在

EF學習筆記(十實施繼承

long cannot oid data- turn cati com list pac 學習總目錄:ASP.NET MVC5 及 EF6 學習筆記 - (目錄整理) 上篇鏈接:EF學習筆記(十) 處理並發 本篇原文鏈接:Implementing Inheritance 面

R語言學習筆記(十廣義線性模型

學習筆記 Education 5.0 1.3 style only 可能性 div erro #Logistic 回歸 install.packages("AER") data(Affairs,package="AER") summary(Affairs) a