一、繪制文字
除了繪制圖形以外,還可以使用QPainter::darwText()函數來繪制文字,也可以使用QPainter::setFont()設置文字所使用的字體,使用QPainter::fontInfo()函數可以獲取字體的信息,它返回QFontInfo類對象。在繪制文字時會默認使用抗鋸齒。
1.1 基本繪制
下面仍然在上一節的程序中進行代碼演示,更改paintEvent()的內容如下:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawText(100, 100, "qter.org-yafeilinux");
}
這樣就在(100, 100)的位置繪制了一個字符串。效果如下圖所示。
1.2 控制文字的位置
我們先到QPainter的幫助文檔頁面,然后查看drawText()函數的重載形式,找到:
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類來設置文字字體。大家也可以先在幫助文檔中查看該類的介紹。下面將最常用的一些設置進行演示。
將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");
//使用字體
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)繪制了文字。后面又將坐標系統平移並旋轉,然后再次繪制了文字。運行程序,效果如下圖所示。
二、繪制路徑
如果要繪制一個復雜的圖形,那么可以使用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)點進行后面的繪制。程序運行效果如下圖所示
三、繪制圖片
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);
運行效果如下圖所示。
四、復合模式
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模式。運行效果如下圖所示。
參考: