Qt中的二維繪圖基本功能是使用Qpainter在繪圖設備上進行繪圖,繪圖設備由QpainterDevice提供,QPaintDevice是一個二維空間的抽象,可以使用QPainter在其上進行繪製,它是所有可以進行繪製的對象的基類。QPainterDevice的子類主要有QWidget, QPixmap,QPicture,QImage,QPinter,QOpenGIPainterDevice,這些設備相當於爲QPainter提供了一個畫布。通過繪製一些基本的圖形,如點,線,圓組成自己需要的圖圖件,形,得到的圖形是不可交互的。
Qt中的Graphics View架構,使用QGraphicsView,QGraphicsScene,QGraphicsItem類繪圖,在一個場景中可以繪製,且圖件是可以交互的。
1. QPainter基本繪圖:
在繪圖系統中,主要通過QPainter完成具體的繪圖操作,QPaintDevice是一個可以用QPainter進行繪圖的抽象二維畫布。QPainterEngine爲QPainter提供在不同設備上進行繪圖的接口,QPainterEngine類一般只在QPainter類和QPaintDevice類的內部使用,一般不需要我們去操作它。
QPainter在一個Paint Event事件函數中進行繪圖,從畫布(QWidget, QPixmap, QPicture, QImage, QPinter, QOpenGIPainterDevice )繼承的類都有Paint Event事件函數。例如創建一個Widget窗口,進行繪圖,則這個Widget窗口就是需要使用的繪圖設備。
繪圖的區域就是Widget內部的區域,區域內的座標系統的單位是像素,左上角爲原點(0,0),向右是X軸正向,向下是Y軸正向。繪圖區域的大小可以由Widget::width()以及Widget::height()得到。
QPainter繪圖的屬性:
1. pen屬性:是一個QPen對象,用於控制線條的顏色,寬度,線型等屬性
2. brush屬性:是一個QBrush對象,控制區域填充特性,如顏色,填充方式,漸變特性
3. font:QFont對象,用於繪製文字時控制文字的屬性,字體,大小等
1. 首先聲明繪圖事件處理函數:
protected:
void paintEvent(QPaintEvent* event);
2.在paintEvent()函數中編寫繪製圖像的代碼:
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中間區域矩形框
// QPainter屬性 pen,brush,font
QPen pen;
pen.setWidth(3); // 設置線寬
pen.setColor(Qt::blue);
pen.setStyle(Qt::SolidLine); // 線的樣式
pen.setCapStyle(Qt::FlatCap); // 線條的端點樣式
pen.setJoinStyle(Qt::BevelJoin); // 連接點的樣式
painter.setPen(pen); // 設置QPainter的pen屬性
// brush屬性
QBrush brush;
brush.setColor(Qt::green); // 填充顏色
brush.setStyle(Qt::SolidPattern); // 填充樣式
painter.setBrush(brush);
// 繪圖
painter.drawRect(rect);
// 繪製直線
pen.setColor(Qt::red);
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
painter.drawLine(QPoint(5, 5), QPoint(width-10, height-10));
}
繪圖結果:
關於繪製圖像中的抗鋸齒,可以參考博客:https://blog.csdn.net/xiezhongyuan07/article/details/97116491
同時,可以擦除矩形中填充的顏色,以及重新填充:
painter.eraseRect(rect); // 擦除矩形區域的內容
// 可以重新填充矩形區域
brush.setColor(Qt::black);
painter.fillRect(rect, brush);
QPainter的三個屬性介紹:
1. QPen的屬性:
Qpen主要用於在繪圖時對線條進行控制,包括線寬,顏色,線型的。
QPen主要的接口函數有:
更改器:(設置屬性)
1.pen.setColor(Qt::red); 設置顏色
2.pen.setCapStyle(Qt::FlatCap); 設置端點樣式
3. pen.setJoinStyle(Qt::BevelJoin); 設置連接樣式
4. pen.setWidth() 設置寬度
5. pen.setStyle() 設置樣式
訪問器:(獲取屬性)
1.pen.color(Qt::red); 獲取pen的顏色
2.pen.capStyle(Qt::FlatCap); 獲取端點樣式
3. pen.joinStyle(Qt::BevelJoin); 連接樣式
4. pen.width() 寬度
5. pen.style() 樣式
線條樣式主要有六種:
1. SolidLine
2. DashLine
3. DotLine
4. DashDotLine
5. DashDotDotLine
6. CustomDashLine
7.NoPen
端點樣式有三種:
1. SquareCap
2. FlatCap
3. RoundCap
連接樣式也有三種:
1. BevelJoin
2. MiterJoin
3. RoundJoin
2. QBrush介紹:
QBrush定義了QPainter繪圖時的填充性能,包括顏色,填充樣式,填充材質。
QBrush的主要函數有以下幾種:
void setColor ( Qt::GlobalColor color )
void setStyle ( Qt::BrushStyle style )
void setTexture ( const QPixmap & pixmap )
void setTextureImage ( const QImage & image )
填充樣式setStyle()的參數是一個枚舉類型,主要有以下幾種:
例如,用幾種不同的方式填充矩形區域:
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中間區域矩形框
// brush屬性
QBrush brush;
brush.setColor(Qt::red); // 填充顏色
// brush.setStyle(Qt::SolidPattern); // 填充樣式
// brush.setStyle(Qt::Dense7Pattern);
// brush.setStyle(Qt::CrossPattern);
brush.setStyle(Qt::FDiagPattern);
painter.setBrush(brush);
// 繪圖
painter.drawRect(rect);
}
QBrush填充漸變顏色:
Qt中有三種漸變的效果,如下圖所示:
1. QLinearGradient
線性漸變顏色,可以指定一個起點顏色,終點顏色,還可以指定中間顏色,起點和終點之間可以進行插值計算,得到線性漸變的填充顏色。
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
QRect rect(width/4, height/4, width/2, height/2); // 中間區域矩形框
QLinearGradient linearGrident(width/4, height/4, width/2, height/2); // 指定漸變區域
linearGrident.setColorAt(0, Qt::red);
linearGrident.setColorAt(0.5, Qt::yellow);
linearGrident.setColorAt(1, Qt::blue);
// brush屬性
QBrush brush;
painter.setBrush(linearGrident);
// 繪圖
painter.drawRect(rect);
}
填充效果:
2.QConicalGradient: 圓錐形漸變,即圍繞一箇中心點逆時針生成漸變顏色。
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
QConicalGradient gradient(width/2, height/2, 0); // 填充參數參數cx, cy, start_angle,
gradient.setColorAt(0, Qt::red); // 起始角度的位置,與線性漸變一樣,也是採用相對位置
gradient.setColorAt(0.4, Qt::green);
gradient.setColorAt(0.6, Qt::yellow);
gradient.setColorAt(1, Qt::black);
painter.setBrush(gradient);
painter.drawRect(this->rect()); // 畫圓的區域
}
填充效果:
3. QRadialGradient: 輻射漸變填充,有簡單輻射漸變和擴展輻射漸變兩種方式,簡單輻射漸變是在一個圓內一個焦點和一個端點之間生成漸變顏色,擴展輻射漸變是在一個焦點圓和一箇中心圓之間生成漸變顏色。
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
// 徑向漸變 c_x, c_y, radius, fx, fy 其中fx,fy爲焦點
// c_x, c_y是輻射的中心點,radius是輻射半徑
QRadialGradient gradient(width/2, height/2, qMax(width/4, height/4), width/2, height/2); // 徑向漸變
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(1, Qt::black); // 這裏使用的是邏輯座標 0開始位置 1結束位置
// gradient.setSpread(QGradient::PadSpread); // 設置漸變區域之外的漸變方式,即延展方式
// gradient.setSpread(QGradient::RepeatSpread);
gradient.setSpread(QGradient::ReflectSpread);
painter.setBrush(gradient);
painter.drawRect(this->rect()); // 畫圓的區域
}
同時,QRadialGradient需要通過setSpread()函數設置延展方式,也就是填充區域意外的填充方式,共有三種方式:
下面是填充的效果:
PadSpread:
RepeatSpread:
ReflectSpread:
QPainter繪製基本圖形元件:
QPainter可以繪製包括點,直線,曲線,矩形,圓弧等各種基本線條。具體的函數以及參數可以參考Qt文檔:(文檔部分)
座標系統和座標變換:
QPainter在窗口上繪圖的默認座標是繪圖設備的物理座標,爲了繪圖方便,QPainter提供了一些座標變換功能,通過平移,旋轉等座標變換,得到一個邏輯座標系統,使用邏輯座標系統在某些時候繪圖會更加方便。
常用的座標變換:
1. 平移變換:
void translate(dx, dy):表示將座標系統的原點移動到(dx, dy)位置。移動的單位爲像素。
2. 座標旋轉:
void rotate(angle): 將座標系統繞座標原點旋轉指定的角度。angle>0表示順勢正旋轉,angle<0表示逆時針旋轉。
3.縮放:
void scale(sx, sy): 表示縮放,sx,sy表示沿着x,y軸的縮放比例。參數大於1表示放大,參數小於1表示縮小。
4. 狀態保存於恢復:
在進行座標變換的時候,QPainter內部會有一個座標變換的矩陣,用save()函數保存座標的狀態。用restore()表示恢復保存的座標狀態。這兩個函數必須配對使用。resetTransform表示復位所有的變換操作。
例子:
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); // this代表Widget,及繪圖設備
painter.setRenderHint(QPainter::Antialiasing); // 繪畫普通圖形啓用反走樣, 即開啓抗鋸齒
painter.setRenderHint(QPainter::TextAntialiasing); // 繪畫文字反走樣, 即開啓抗鋸齒
int width = this->width(); // 獲取繪圖區域的大小
int height = this->height();
// 生成五角星的五個頂點座標
int radius = 100; // 半徑
const double Pi = 3.1415926;
double deg = 360.0 / 5 * Pi / 180.0;
QPoint points[5] = {
QPoint(radius, 0),
QPoint(radius * cos(deg), radius * sin(deg)),
QPoint(radius * cos(2*deg), radius * sin(2*deg)),
QPoint(radius * cos(3*deg), radius * sin(3*deg)),
QPoint(radius * cos(4*deg), radius * sin(4*deg))
};
// 設置字體
QFont font;
font.setPointSize(12);
font.setBold(true);
painter.setFont(font);
// 設置畫筆
QPen pen;
pen.setWidth(2); // 設置線寬
pen.setColor(Qt::blue); // 設置顏色
pen.setStyle(Qt::SolidLine); // 設置線型
pen.setCapStyle(Qt::FlatCap);
pen.setJoinStyle(Qt::BevelJoin);
painter.setPen(pen);
// 設置畫刷
QBrush brush;
brush.setColor(Qt::red);
brush.setStyle(Qt::SolidPattern);
painter.setBrush(brush);
// painter_path, 可以重複使用
QPainterPath path;
path.moveTo(points[0]); // 起始點
path.lineTo(points[2]);
path.lineTo(points[4]);
path.lineTo(points[1]);
path.lineTo(points[3]);
path.closeSubpath(); // 閉合路徑,相當於 path.lineTo(points[0]);
// 添加文本
path.addText(points[0], font, "1");
path.addText(points[1], font, "2");
path.addText(points[2], font, "3");
path.addText(points[3], font, "4");
path.addText(points[4], font, "5");
// 保存座標狀態
painter.save();
painter.translate(width/4, height/4); // 平移
painter.drawPath(path);
// 恢復座標
painter.restore();
painter.translate(width/2, height/2); // 平移
painter.scale(0.6, 0.6); // 縮放,縮小操作
painter.rotate(30); // 旋轉
painter.drawPath(path); // 這裏的path重複利用了
}
繪製效果圖:
QPainterPath可以記錄幾個點的連線過程,可以對繪製複雜圖像的過程進行記錄,便於重複使用。