QT5簡易座標系和折線圖的繪製

https://blog.csdn.net/a343902152/article/details/47021781

  1. QT座標系統。

在畫座標系之前,我們得先了解一下QT5的座標系統。

QT5的座標設定左上角爲原點(0,0),向右爲x軸正方向,向下爲y軸正方向,這點與生活中常見的直角座標系不同。



2. 繪製直角座標系

    2.1 添加頭文件

     #include<QPaintEvent> //用於繪畫事件

  #include<QtGui> //引入用到的控件

   

    2.2  添加畫布

    我們選擇在一個畫布上進行繪畫。

    在mainwindow.h處添加一個QImage對象image如下:

  1. private:
  2. Ui::MainWindow *ui;
  3. QImage image;
  1. <span style="font-size:12px;">
  2. 然後在Mainwindow的構造函數中,對畫布image進行初始化。</span>


  1. <span style="font-size:12px;">MainWindow::MainWindow(QWidget *parent) :
  2. QMainWindow(parent),
  3. ui(new Ui::MainWindow)
  4. {
  5. ui->setupUi(this);
  6. image = QImage(600,300,QImage::Format_RGB32); //畫布的初始化大小設爲600*500,使用32位顏色
  7. QColor backColor = qRgb(255,255,255); //畫布初始化背景色使用白色
  8. image.fill(backColor);//對畫布進行填充
  9. }</span>
這樣,我們就添加好了一塊寬度爲600,高度300的白色畫布。

2.3 重載繪畫函數paintEvent

   在Mainwindow.h 處添加:

  1. protected:
  2. void paintEvent(QPaintEvent *){
  3. QPainter painter(this);
  4. painter.drawImage(0,0,image);
  5. }


表示每當界面有變,便在在(0,0)處開始繪製之前好的image圖像。

運行程序查看效果:

將界面拉大,可以看到存在一片白色區域,這就是我們定義的image的圖像。而外圍的灰色部分爲沒有被覆蓋到的區域。

2.4 利用QPainter在畫布image上繪圖

新建一個Paint函數如下:

  1. voidMainWindow::Paint()
  2. {
  3. QPainter painter(&image);
  4. painter.setRenderHint(QPainter::Antialiasing, true);//設置反鋸齒模式,好看一點
  5. int pointx=35,pointy=280;//確定座標軸起點座標,這裏定義(35,280)
  6. int width=580-pointx,height=260;//確定座標軸寬度跟高度 上文定義畫布爲600X300,寬高依此而定。
  7. //繪製座標軸 座標軸原點(35,280)
  8. painter.drawRect(5,5,600-10,300-10);//外圍的矩形,從(5,5)起,到(590,290)結束,周圍留了5的間隙。
  9. painter.drawLine(pointx,pointy,width+pointx,pointy);//座標軸x寬度爲width
  10. painter.drawLine(pointx,pointy-height,pointx,pointy);//座標軸y高度爲height
  11. }


然後在Mainwindow的構造函數中調用(方便起見,實際上哪裏需要畫圖就在哪裏調用)

  1. MainWindow::MainWindow(QWidget *parent) :
  2. QMainWindow(parent),
  3. ui(new Ui::MainWindow)
  4. {
  5. ui->setupUi(this);
  6. image = QImage(600,300,QImage::Format_RGB32); //畫布的初始化大小設爲600*500,使用32位顏色
  7. QColor backColor = qRgb(255,255,255); //畫布初始化背景色使用白色
  8. image.fill(backColor);//對畫布進行填充
  9. Paint();
  10. }


運行程序,可以看到,此時已經畫出了一個外圍的矩形框,以及未標刻度的x,y軸。注意座標軸原點位於左下方,但是他的座標並不是近似(35,0)而是(35,280)。由於要繪製折線圖,而折線圖的數據量和大小是不確定的,而座標刻度要由此而定,所以暫時先不繪製刻度,而是先處理折線圖數據。

3. 繪製折線圖

3.1 折線圖原理與處理數據

繪製折線圖只要將所有數據對應的點按順序連起來即可。即將(i,a[i])和(i+1,a[i+1])連接。

拿到一組數據,首先找出其最大值和最小值,並將其位置記錄下來。另外還可選擇記錄數據總和、平均值等情況。

這裏採用隨機生成數據的方法爲數組a賦值。

  1. srand(time(NULL));
  2. //獲得數據中最大值和最小值、平均數
  3. int n=30;//n爲數據個數
  4. double sum=0;
  5. double ave=0;
  6. int _ma=0;//數組裏的最大值
  7. int _mi=inf;//inf爲 #define inf 0x3f3f3f3f
  8. int a[n];//數據儲存在數組a中,大小爲n
  9. for(int i=0;i<n;i++)
  10. a[i]=rand()%40+20;
  11. int maxpos=0,minpos=0;
  12. for(int i=0;i<n;i++)
  13. {
  14. sum+=a[i];
  15. if(a[i]>_ma){
  16. _ma=a[i];
  17. maxpos=i;
  18. }
  19. if(a[i]<_mi){
  20. _mi=a[i];
  21. minpos=i;
  22. }
  23. }
  24. ave=sum/n;//平均數


3.2 計算x,y軸比例係數,描點連線

  1. doublekx=(double)width/(n-1);//x軸的係數
  2. double ky=(double)height/_ma;//y方向的比例係數
  3.   QPen pen,penPoint;
  4. pen.setColor(Qt::black);
  5. pen.setWidth(2);
  6. penPoint.setColor(Qt::blue);
  7. penPoint.setWidth(5);
  8. for(int i=0;i<n-1;i++)
  9. {
  10. //由於y軸是倒着的,所以y軸座標要pointy-a[i]*ky 其中ky爲比例係數
  11. painter.setPen(pen);//黑色筆用於連線
  12. painter.drawLine(pointx+kx*i,pointy-a[i]*ky,pointx+kx*(i+1),pointy-a[i+1]*ky);
  13. painter.setPen(penPoint);//藍色的筆,用於標記各個點
  14. painter.drawPoint(pointx+kx*i,pointy-a[i]*ky);
  15. }
  16. painter.drawPoint(pointx+kx*(n-1),pointy-a[n-1]*ky);//繪製最後一個點


把x軸評分給n個數據,所以kx=width/(n-1)(第一個數據在y軸上,所以總共有n-1個間隔)。

這裏假設數據均爲正數,所以ky這樣定義、,如果存在負數,或者只想顯示最小值和最大值之間的那一段數據,可以將ky改爲

double ky=(double)/(_ma-_mi);//y方向的比例係數


如果只想在座標軸的某一部分顯示圖像,還可爲將ky改爲帶有length的等等,如:

double ky=(double)length*0.4/(_ma-_mi);//y方向的比例係數


3.3 畫上平均值,標記上最大值和最小值

  1. //繪製平均線
  2. QPen penAve;
  3. penAve.setColor(Qt::red);//選擇紅色
  4. penAve.setWidth(2);
  5. penAve.setStyle(Qt::DotLine);//線條類型爲虛線
  6. painter.setPen(penAve);
  7. painter.drawLine(pointx,pointy-ave*ky,pointx+width,pointy-ave*ky);
  8. //繪製最大值和最小值
  9. QPen penMaxMin;
  10. penMaxMin.setColor(Qt::darkGreen);//暗綠色
  11. painter.setPen(penMaxMin);
  12. painter.drawText(pointx+kx*maxpos-kx,pointy-a[maxpos]*ky-5,
  13. "最大值"+QString::number(_ma));
  14. painter.drawText(pointx+kx*minpos-kx,pointy-a[minpos]*ky+15,
  15. "最小值"+QString::number(_mi));
  16. penMaxMin.setColor(Qt::red);
  17. penMaxMin.setWidth(7);
  18. painter.setPen(penMaxMin);
  19.  painter.drawPoint(pointx+kx*maxpos,pointy-a[maxpos]*ky);//標記最大值點
  20. painter.drawPoint(pointx+kx*minpos,pointy-a[minpos]*ky);//標記最小值點


4. 根據數據爲座標軸添加刻度

  1. //繪製刻度線
  2. QPen penDegree;
  3. penDegree.setColor(Qt::black);
  4. penDegree.setWidth(2);
  5. painter.setPen(penDegree);
  6. //畫上x軸刻度線
  7. for(int i=0;i<10;i++)//分成10份
  8. {
  9. //選取合適的座標,繪製一段長度爲4的直線,用於表示刻度
  10. painter.drawLine(pointx+(i+1)*width/10,pointy,pointx+(i+1)*width/10,pointy+4);
  11. painter.drawText(pointx+(i+0.65)*width/10,
  12. pointy+10,QString::number((int)((i+1)*((double)n/10))));
  13. }
  14. //y軸刻度線
  15. double _maStep=(double)_ma/10;//y軸刻度間隔需根據最大值來表示
  16. for(int i=0;i<10;i++)
  17. {
  18. //主要就是確定一個位置,然後畫一條短短的直線表示刻度。
  19. painter.drawLine(pointx,pointy-(i+1)*height/10,
  20. pointx-4,pointy-(i+1)*height/10);
  21. painter.drawText(pointx-20,pointy-(i+0.85)*height/10,
  22. QString::number((int)(_maStep*(i+1))));
  23. }

刻度的間隔可自由掌控,比如:

double ky=(double)length*0.4/(_ma-_mi);//y方向的比例係數


等...


至此,一個簡易的QT座標系和折線圖就繪製完成了奮鬥

源碼可在此處下載

鏈接:http://pan.baidu.com/s/1hqkyVEc 密碼:a58k

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