原理
- QPainter用來執行繪圖操作
- QPaintDevice提供繪圖設備,它是一個二維空間的抽象,可以使用QPainter在其上進行繪製
- QPaintEngine介於QPainter和QPaintDevice對象之間,它的存在使得QPainter可以以統一的方法在不同QPaintDevice上繪圖
QPainter類
常用函數
1.設置繪圖工具
- setPen //設置畫筆
- setBrush //設置畫刷
- setFont //設置字體
- setBackgroundMode //設置背景模式
2.繪製圖形和文字
- drawPoint() //點
- drawPoints() //多個點
- drawLine() //線
- drawLines() //多條線
- drawRect() //矩形
- drawRects() //多個矩形
- drawRoundedRect() //圓角矩形
- drawEllipse() //橢圓
- drawArc() //圓弧
- drawPie() //扇形圖
- drawPolyline() //多折線
- drawPolygon() //多邊形
- drawConvexPolygon() //凸多邊形
- drawPixmap()/ drawImage() //位圖
- drawText() //文字
- drawPath() //按路徑繪製
painter->drawLine(20, 20, 100, 120); //畫一條 (20,20) 到 (100,120) 的線段
painter->drawEllipse(20,20,210,160); //橢圓左上角的座標+橢圓的寬度和高度
painter->drawRect(20,20,210,160); //矩形左上角座標+寬和高
painter->drawRoundRect(20,20,210,160,50,50); //最後兩個參數決定圓角大小,可爲0到99的數值(99代表圓)
paint->drawPie(20,20,210,160,0,500); //前四個參數定義與drawEllipse()相同。後兩個參數定義圓的樣式。0爲起始角度(單 位爲1/16度),500爲扇形所展開的角度(單位也爲1/16度)
paint->drawArc(20,20,210,160,500,1000); //drawArc()函數與drawPie()函數的參數完全相同
3.座標變換
- rotate() //旋轉
- translate() //平移
- scale() //縮放
- shear() //扭曲
繪圖一般流程
-
定義QPainter對象(變量)
-
在paintEvent函數中,使用對象的方法(成員函數)繪製各種圖形或文字
-
也可以在其他事件處理函數中用以上方法繪圖,並且調用repaint函數重新刷新屏幕(重繪)
舉例
1.Widget.h
protected:
void paintEvent(QPaintEvent *); //函數名和參數不能錯,不是自定義函數
2.Widget.cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(Qt::blue); //設置藍色畫筆
painter.setFont(QFont("Arial", 30)); //設置字體
//在客戶區中央輸出文字
painter.drawText(rect(), Qt::AlignCenter, "Qt");
painter.drawEllipse(QRect(0, 0, width()-1, height()-1));
}
運行結果:
QPen類
點類(QPoint 和 QPointF)
QPoint或QPointF 類代表一個座標點。它包含一個橫座標和一個縱座標,前者數值爲int型,後者數值爲float型。
- void setX(int x); //設置橫座標爲 x
- void setY(int y); //設置縱座標爲 y
舉例
1.畫直線
QPoint p1(0,0), p2(100,100);
painter.drawLine(p1,p2);
2.畫多邊形
QPoint points[4] = {
QPoint(10,80),QPoint(20,10),
QPoint(80,30),QPoint(90,70)
};
painter.drawPolygon(points, 4);
線段類(QLine 和 QLineF)
Qline 和 QLineF代表一個線段,前者數值爲int型,後者數值爲float型。
構造函數
-
QLine::QLine(const QPoint & p1,const QPoint & p2) //線段(x1,y1)到(x2,y2)
QLine::QLine(int x1, int y1, int x2, int y2)
其他函數
- void QLine::setP1(const QPoint & p1) //設置點1
- void QLine::setP2(const QPoint & p2) //設置點2
- void QLine::setLine(int x1, int y1, int x2, int y2 //設置點(x1,y1)和(x2,y2)
- int x1() / x2() / y1() / y2() //返回座標x1,x2,y1,y2
矩形類(QRect 和 QRectF)
構造函數
- QRect r1(100, 200, 110, 160); //矩形對象 r1的左上角爲(100,200),寬110、高160
其他函數
- int x(); //獲取左上角x坐
- int y(); //獲取左上角y座標
- void setX(int x); //設置左上角x座標
- void setY(int y); //設置左上角y座標
- int width(); //獲取矩形寬度
- int height(); //獲取矩形高度
- void setWidth(int width); //設置矩形寬度
- void setHeight(int height); //設置矩形高度
- void moveTo(int x, int y) //將矩形左上角移動到(x,y)
- void moveTo(const QPoint & pos) //將矩形左上角移動到座標點pos
- QPoint center () //返回矩形中心點
- bool contains ( int x, int y ) //判斷點是否在當前矩形內部
- bool contains(const QPoint &point, bool proper=false)
顏色類(QColor)
QColor支持RGB、HSV、CMYK顏色模型。還支持alpha混合(透明度)的模式。RGB是面向硬件的模型,顏色由紅綠藍三種基色混合而成。
- QColor( 250, 250, 200) //定義顏色對象,紅綠藍分別是250、250、200
- QColor(255, 0, 0, 127) // 第四個爲透明度(其中透明度爲0~255,0爲完全透明、255爲不透明)
- QColor(Qt::green) //使用Qt的枚舉類型
屏幕重繪
在Qt中,paintEvent函數是進行重繪的。只要出現以下幾種情況,系統就會產生屏幕重繪事件,從而自動調用paintEvent方法。
- 當窗口部件第一次顯示時;
- 重新調整窗口部件大小,或者窗口從隱藏到顯示;
- 當窗口部件被其他部件遮擋,然後又再次顯示出來時,就會對隱藏的區域產生一個重繪事件。
但是如果遇到如下情況:
-
有些時候,程序窗口並沒有發生大小改變或從隱藏到顯示等情況(即沒有產生屏幕重繪事件),但是由於某種情況的發生也需要對窗口進行重繪。
-
比如要實現用戶點擊窗口內任意位置就在此處畫一個圓,或者隨着時間流逝週期性的在窗口中顯示時間,這時就需要主動地進行屏幕重繪。
此時就需要QWidget的函數update()或者repaint()可以實現主動屏幕重繪(就是調用一次paintEvent函數?應該是。。)。
update()和 repaint()差別:
- repaint()函數被調用之後,立即執行重繪。因此repaint最快的;
- update()調用後並不立即重繪,而是將重繪事件放入事件循環中,由主窗口的事件循環來統一調度
update()函數
- void QWidget::update(int x, int y, int w, int h) //重繪(x, y)爲左上角,w爲寬,h爲高的區域(重繪一個矩形區域)
- void QWidget::update(const QRect & rect)
除此之外,還有timerEvent函數,它在timer每次到時間時都會被觸發一次
簡單實例(文字,線段,矩形,橢圓,圖片的繪製)
綜合實例——時鐘的繪製
新建基於QWidget類的程序。創建時取消ui界面
1.Widget.h
float radius; // 時鐘半徑
//指針針尖座標
int xSecond, ySecond, xMinute, yMinute, xHour, yHour;
int xCenter, yCenter; //時鐘中心座標
int second,minute,hour; //時分秒的實際數字
void CalcPosition(); //計算三種指針針尖座標的函數
protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *event);
2.Widget.cpp
#include <qmath.h> // 數學庫
#include <QPainter>
#define PI 3.14159265 // 圓周率
void Widget::CalcPosition()
{ float secondHandLen, minuteHandLen, hourHandLen;
secondHandLen = radius*0.8; //計算秒針長度
minuteHandLen = radius*0.65; //計算分針長度
hourHandLen = radius*0.5; //計算時針長度
// 計算秒針針尖位置
xSecond = xCenter+secondHandLen*cos(second*PI/30-PI/2);
ySecond = yCenter+secondHandLen*sin(second*PI/30-PI/2);
// 計算分針針尖位置
xMinute = xCenter+minuteHandLen*cos(minute*PI/30-PI/2);
yMinute = yCenter+minuteHandLen*sin(minute*PI/30-PI/2);
// 計算時針針尖位置
xHour=xCenter + hourHandLen*cos((hour+1.0*minute/60)*PI/6-PI/2);
yHour = yCenter + hourHandLen*sin((hour+1.0*minute/60)*PI/6-PI/2);
}
Widget::Widget(QWidget *parent) : QWidget(parent)
{
radius = 100;
xCenter = 120, yCenter=120;
hour = 3, minute = 56, second = 55; //初始時間 3:56:55
CalcPosition(); //計算初始位置用於第一次顯示
startTimer(100); //啓動定時器,爲了便於觀察,加速10倍
}
void Widget::timerEvent(QTimerEvent *e)
{
CalcPosition(); // 計算位置
second++; // 秒增加
if(second==60)
{
second = 0;
minute++; // 分增加
}
if(minute==60) {
minute = 0;
hour++; // 時增加
}
update();
}
void Widget::paintEvent(QPaintEvent *) {
QPainter painter(this);
QPen pen; // 畫筆的使用請參考下一節
painter.drawEllipse(QPointF(120.0,120.0),radius,radius);
painter.drawLine(xCenter,yCenter, xSecond,ySecond); //秒針
pen.setWidth(2); // 畫筆設置寬度
painter.setPen(pen); //使用畫筆
painter.drawLine(xCenter,yCenter, xMinute,yMinute); //分針
pen.setWidth(4);
painter.setPen(pen);
painter.drawLine(xCenter,yCenter, xHour,yHour); // 時針
}
CalcPosition() 函數中計算針尖角度其實可以不用這麼繞來繞去,ppt中給出的解釋是:
注意,Qt中座標是x軸橫向向右爲正,y軸垂直向下爲正,所以0度對應水平向右,順時針方向是度數增加。但是鐘錶應該是豎直向上位置爲0度,順時針方向爲度數增加。所以這裏計算旋轉度數時減去PI/2弧度(即90度)。
可以畫個sin和cos的波浪圖,然後看指針轉一圈對於x和y軸是要加還是要減,與波浪圖相對應即可,不行的話+/- π/2 即可(左加右減)