【Qt】二維繪圖

 

原理

  • QPainter用來執行繪圖操作
  • QPaintDevice提供繪圖設備,它是一個二維空間的抽象,可以使用QPainter在其上進行繪製
  • QPaintEngine介於QPainterQPaintDevice對象之間,它的存在使得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()          //扭曲

繪圖一般流程

  1. 定義QPainter對象(變量)

  2. paintEvent函數中,使用對象的方法(成員函數)繪製各種圖形或文字

  3. 也可以在其他事件處理函數中用以上方法繪圖,並且調用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類

QT Road之【QPen】

 

點類(QPoint 和 QPointF) 

 QPointQPointF 類代表一個座標點。它包含一個橫座標和一個縱座標,前者數值爲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支持RGBHSVCMYK顏色模型。還支持alpha混合(透明度)的模式。RGB是面向硬件的模型,顏色由紅綠藍三種基色混合而成。

  • QColor( 250, 250, 200)     //定義顏色對象,紅綠藍分別是250250200
  • QColor(255, 0, 0, 127)      // 第四個爲透明度(其中透明度爲0~2550完全透明、255爲不透明)
  • QColor(Qt::green)             //使用Qt的枚舉類型

 

屏幕重繪

Qt中,paintEvent函數是進行重繪的。只要出現以下幾種情況,系統就會產生屏幕重繪事件,從而自動調用paintEvent方法。

  1. 當窗口部件第一次顯示時
  2. 重新調整窗口部件大小,或者窗口從隱藏到顯示;
  3. 當窗口部件被其他部件遮擋,然後又再次顯示出來時,就會對隱藏的區域產生一個重繪事件

但是如果遇到如下情況:

  • 有些時候,程序窗口並沒有發生大小改變或從隱藏到顯示等情況(即沒有產生屏幕重繪事件),但是由於某種情況的發生也需要對窗口進行重繪。

  • 比如要實現用戶點擊窗口內任意位置就在此處畫一個圓,或者隨着時間流逝週期性的在窗口中顯示時間,這時就需要主動地進行屏幕重繪。

此時就需要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每次到時間時都會被觸發一次

 

簡單實例(文字,線段,矩形,橢圓,圖片的繪製)

Qt 之圖形(QPainter 的基本繪圖)

 

綜合實例——時鐘的繪製

新建基於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 即可(左加右減)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章