Qt 2D繪圖之三:繪製文字、路徑、圖像、複合模式

1、繪製文字

除了繪製圖形之外,還可使用QPainter::darwText()函數來繪製文字,也可使用QPainter::setFont()設置文字所使用的字體,使用QPainter::fontInfo()函數能夠獲取字體的信息,它返回QFontInfo類對象。在繪製文字時會默認使用抗鋸齒。php


1.1 基本繪製

下面仍然在上一節的程序中進行代碼演示,更改paintEvent()的內容以下:linux

void Widget::paintEvent(QPaintEvent *)
{    
      QPainter painter(this);    
      painter.drawText(100, 100,  "qter.org-yafeilinux");
}

這樣就在(100, 100)的位置繪製了一個字符串。效果以下圖所示。c++


1.2 控制文字的位置

咱們先到QPainter的幫助文檔頁面,而後查看drawText()函數的重載形式,找到:api

QPainter::drawText ( const QRectF & rectangle, int flags, const QString & text, QRectF * boundingRect = 0 )
  • 第一個參數指定了繪製文字所在的矩形;
  • 第二個參數指定了文字在矩形中的對齊方式,它由Qt::AlignmentFlag枚舉類型進行定義,不一樣對齊方式也可使用「|」操做符同時使用,這裏還可使用Qt::TextFlag定義的其餘一些標誌,好比自動換行等;
  • 第三個參數就是所要繪製的文字,這裏可使用「\n」來實現換行;
  • 第四個參數通常不用設置。

下面來看一個例子。爲了更明顯地看到文字在指定矩形中的位置,咱們繪製出這個矩形。將paintEvent()函數更改以下:函數

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    //設置一個矩形
    QRectF rect(50, 50, 300, 200);
    //爲了更直觀地看到字體的位置,咱們繪製出這個矩形
    painter.drawRect(rect);
    painter.setPen(QColor(Qt::red));
    //這裏先讓字體水平居中
    painter.drawText(rect, Qt::AlignHCenter, "yafeilinux");
}

如今運行程序,效果以下圖所示。字體


可用的對齊方式以下圖所示。優化


1.3 使用字體

爲了繪製漂亮的文字,可使用QFont類來設置文字字體。你們也能夠先在幫助文檔中查看該類的介紹。下面將最經常使用的一些設置進行演示。ui

將paintEvent()函數更改以下:this

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    //設置一個矩形
    QRectF rect(50, 50, 300, 200);
    //爲了更直觀地看到字體的位置,咱們繪製出這個矩形
    painter.drawRect(rect);
    painter.setPen(QColor(Qt::red));
    //這裏先讓字體水平居中
    painter.drawText(rect, Qt::AlignHCenter, "yafeilinux");

    //使用字體
    QFont font("宋體", 15, QFont::Bold, true);
    //設置下劃線
    font.setUnderline(true);
    //設置上劃線
    font.setOverline(true);
    //設置字母大小寫
    font.setCapitalization(QFont::SmallCaps);
    //設置字符間的間距
    font.setLetterSpacing(QFont::AbsoluteSpacing, 10);
    //使用字體
    painter.setFont(font);
    painter.setPen(Qt::blue);
    painter.drawText(120, 80, tr("yafeilinux"));
    painter.translate(50, 50);
    painter.rotate(90);
    painter.drawText(0, 0, tr("helloqt"));
}

這裏建立了QFont字體對象,使用的構造函數爲QFont::QFont ( const QString & family,int pointSize = -1, int weight = -1, bool italic = false ),第一個參數設置字體的family屬性,這裏使用的字體族爲宋體,可使用QFontDatabase類來獲取所支持的全部字體;第二個參數是點大小,默認大小爲12;第三個參數爲weight屬性,這裏使用了粗體;最後一個屬性設置是否使用斜體。而後咱們又使用了其餘幾個函數來設置字體的格式,最後調用setFont()函數來使用該字體,並使用drawText()函數的另外一種重載形式在點(120, 80)繪製了文字。後面又將座標系統平移並旋轉,而後再次繪製了文字。運行程序,效果以下圖所示。spa


2、繪製路徑

若是要繪製一個複雜的圖形,那麼可使用QPainterPath類,而後使用QPainter::drawPath()來進行繪製。QPainterPath類爲繪製操做提供了一個容器,能夠用來建立圖形而且重複使用。一個繪圖路徑就是由多個矩形、橢圓、線條或者曲線等組成的對象,一個路徑能夠是封閉的,例如矩形和橢圓;也能夠是非封閉的,例如線條和曲線。


2.1 簡單應用

下面看一個例子:添加一個橢圓和一根線在圖形路徑裏。依然在前面的項目中進行講解。更改paintEvent()函數以下:

void Widget::paintEvent(QPaintEvent *)
{
    //添加一個橢圓和一根線在圖形路徑裏
    QPainterPath path;
    path.addEllipse(100, 100, 50, 50); //添加一個圓心爲(100,100),橫縱半徑都爲50的橢圓
    path.lineTo(200, 200); //添加一根從當前位置到(200,200)的線
    QPainter painter(this);
    painter.setPen(Qt::blue);
    painter.setBrush(Qt::red);
    painter.drawPath(path);
}

當建立一個QPainterPath對象後,可使用lineTo()、arcTo()、cubicTo()和quadTo()等函數將直線或者曲線添加到路徑中。運行程序,效果以下圖所示。


2.2 複製圖形

若是隻是簡單的將幾個圖形拼接在一塊兒,其實徹底沒有必要用路徑,之因此要引入路徑,就是由於它的一個很是有用的功能:複製圖形路徑。更改paintEvent()函數以下:

void Widget::paintEvent(QPaintEvent *)
{
    //添加一個橢圓和一根線在路徑裏
    QPainterPath path;
    path.addEllipse(100, 100, 50, 50); //添加一個圓心爲(100,100),橫縱半徑都爲50的橢圓
    path.lineTo(200, 200); //添加一根從當前位置到(200,200)的線
    QPainter painter(this);
    painter.setPen(Qt::blue);
    painter.setBrush(Qt::red);
    painter.drawPath(path);

    //複製圖形路徑
    QPainterPath path2;
    path2.addPath(path);
    path2.translate(100,0);
    painter.drawPath(path2);
}

如今運行程序,效果以下圖所示。

能夠看到,對於已經繪製好的路徑,能夠很是簡單地進行重複繪製。


2.3 繪製圖形時的當前位置

咱們先來看一個例子,將paintEvent()函數更改以下:

void Widget::paintEvent(QPaintEvent *)
{
    QPainterPath path;
    path.lineTo(100, 100);
    path.lineTo(200, 100);
    QPainter painter(this);
    painter.drawPath(path);
}

程序運行效果以下圖所示。

能夠看到,建立路徑後,默認是從(0, 0)點開始繪製的,當繪製完第一條直線後當前位置是(100, 100)點,從這裏開始繪製第二條直線。繪製完第二條直線後,當前位置是(200, 100)。


咱們也能夠使用moveTo()函數來改變當前點的位置。例如將paintEvent()函數更改以下:

void Widget::paintEvent(QPaintEvent *)
{
    QPainterPath path;
    path.addRect(50, 50, 40, 40);

    //移動到(100, 100)點
    path.moveTo(100, 100);

    path.lineTo(200, 200);
    QPainter painter(this);
    painter.drawPath(path);
}

這樣當繪製完矩形之後,就會移動到(100, 100)點進行後面的繪製。程序運行效果以下圖所示


3、繪製圖片

Qt提供了四個類來處理圖像數據:QImage、QPixmap、QBitmap和QPicture,它們都是經常使用的繪圖設備。其中QImage主要用來進行I/O處理,它對I/O處理操做進行了優化,並且能夠用來直接訪問和操做像素;QPixmap主要用來在屏幕上顯示圖像,它對在屏幕上顯示圖像進行了優化;QBitmap是QPixmap的子類,用來處理顏色深度爲1的圖像,即只能顯示黑白兩種顏色;QPicture用來記錄並重演QPainter命令。這一節咱們只講解QPixmap。


3.1 簡單繪製圖片

(1)此次咱們從新建立一個Qt Widgets應用,項目名稱爲mypixmap,在類信息頁面,將基類選擇爲QDialog,類名使用默認的Dialog便可。


(2)而後在源碼目錄中複製一張圖片,好比這裏是一張logo.png圖片,以下圖所示。


(3)在dialog.h文件中添加劇繪事件處理函數的聲明:

protected:
    void paintEvent(QPaintEvent *);

(4)到dialog.cpp文件中先添加頭文件包含#include <QPainter>,而後添加函數的定義:

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPixmap pix;
    pix.load("../mypixmap/logo.png");
    painter.drawPixmap(0, 0, 80, 100, pix);
}

這裏使用了相對路徑,由於Qt Creator默認是使用影子構建,即編譯生成的文件在build-mypixmap-Desktop_Qt_5_8_0_MinGW_32bit-Debug這樣的目錄裏面,而這個目錄就是當前目錄,因此源碼目錄就是其上級目錄了。你們能夠根據本身的實際狀況來更改路徑,也可使用絕對路徑,不過最好使用資源文件來存放圖片。drawPixmap()函數在給定的矩形中來繪製圖片,這裏矩形的左上角頂點爲(0, 0)點,寬80,高100,若是寬高跟圖片的大小比例不一樣,默認會拉伸圖片。運行效果以下圖所示。


3.2 平移圖片

QPainter類中的translate()函數實現座標原點的改變,改變原點後,此點將會成爲新的原點(0,0)。下面來看一個例子。在paintEvent()函數中繼續添加以下代碼:

//將(100,100)設爲座標原點
painter.translate(100, 100);
painter.drawPixmap(0, 0, 80, 100, pix);

這裏將(100,100)設置爲了新的座標原點,因此下面在(0,0)點貼圖,就至關於在之前的(100,100)點貼圖。運行程序,效果以下圖所示。


3.3 縮放圖片

咱們可使用QPixmap類中的scaled()函數來實現圖片的放大和縮小。在paintEvent()函數中繼續添加以下代碼:

//得到之前圖片的寬和高
qreal width = pix.width();
qreal height = pix.height();
//將圖片的寬和高都縮小,而且在給定的矩形內保持寬高的比值不變
pix = pix.scaled(width, height,Qt::KeepAspectRatio);
painter.drawPixmap(90, 90, pix);

其中參數Qt::KeepAspectRatio,是圖片縮放的方式。能夠將鼠標指針放到該代碼上,按下F1鍵查看其幫助了,以下圖所示。

這裏有三個值,只看其示例圖片就可大體明白,Qt::IgnoreAspectRatio是不保持圖片的寬高比;Qt::KeepAspectRatio是在給定的矩形中保持寬高比;最後一個也是保持寬高比,但可能超出給定的矩形。這裏給定的矩形是由咱們顯示圖片時給定的參數決定的,例如painter.drawPixmap(0,0,100,100,pix);就是在以(0,0)點爲起始點的寬和高都是100的矩形中。運行程序效果以下圖所示。


3.4 旋轉圖片

旋轉使用的是QPainter類的rotate()函數,它默認是以原點爲中心進行旋轉的。若是要改變旋轉的中心,可使用前面講到的translate()函數完成。在paintEvent()函數中繼續添加以下代碼:

//讓圖片的中心做爲旋轉的中心
painter.translate(40, 50);
painter.rotate(90); //順時針旋轉90度
painter.translate(-40,-50); //使原點復原
painter.drawPixmap(100, 100, 80, 100, pix);

這裏必須先改變旋轉中心,而後再旋轉,而後再將原點復原,才能達到想要的效果。運行程序,以下圖所示。


3.5 扭曲圖片

實現圖片的扭曲,是使用的QPainter類的shear(qreal sh,qreal sv)函數完成的。它有兩個參數,前面的參數實現橫向變形,後面的參數實現縱向變形。當它們的值爲0時,表示不扭曲。在paintEvent()中繼續添加以下代碼:

painter.shear(0.5, 0); //橫向扭曲
painter.drawPixmap(100, 0, 80, 100, pix);

運行效果以下圖所示。


4、複合模式

QPainter提供了複合模式(Composition Modes)來定義如何完成數字圖像的複合,即如何將源圖像的像素和目標圖像的像素進行合併。QPainter提供的經常使用複合模式及其效果以下圖所示。 其中普通的類型是SoiirceOver(一般被稱爲alpha混合),就是正在繪製的源像素混合在已經繪製的目標像素上,源像素的alpha份量定義了它的透明度,這樣源圖像就會以透明效果在目標圖像上進行顯示。當設置了複合模式,它就會應用到全部的繪圖操做中,例如畫筆、畫刷、漸變和pixmap/image繪製等。


實例:

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter;
    QImage image(400, 300, QImage::Format_ARGB32_Premultiplied);
    painter.begin(&image);
    painter.setBrush(Qt::green);
    painter.drawRect(100, 50, 200, 200);
    painter.setBrush(QColor(0, 0, 255, 150));
    painter.drawRect(50, 0, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
    painter.drawRect(250, 0, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
    painter.drawRect(50, 200, 100, 100);
    painter.setCompositionMode(QPainter::CompositionMode_Xor);
    painter.drawRect(250, 200, 100, 100);
    painter.end();
    painter.begin(this);
    painter.drawImage(0, 0, image);
}

這裏先在Qlmage上繪製了一個矩形,而後又在這個矩形的4個角分別繪製了4個小矩形,每一個小矩形都使用了不一樣的複合模式,而且使用了半透明的顏色進行填充。 第一個小矩形沒有明確指定複合模式,它默認使用的是SourceOver模式。運行效果以下圖所示。


參考:

第13篇 Qt5之2D繪圖(三)繪製文字

第14篇 Qt5之2D繪圖(四)繪製路徑

66 2D繪圖(繪製文字、路徑、圖像、模式)

相關文章
相關標籤/搜索