https://blog.csdn.net/a343902152/article/details/47021781
- QT座標系統。
在畫座標系之前,我們得先了解一下QT5的座標系統。
QT5的座標設定左上角爲原點(0,0),向右爲x軸正方向,向下爲y軸正方向,這點與生活中常見的直角座標系不同。
2. 繪製直角座標系
2.1 添加頭文件
#include<QPaintEvent> //用於繪畫事件
#include<QtGui> //引入用到的控件
2.2 添加畫布
我們選擇在一個畫布上進行繪畫。
在mainwindow.h處添加一個QImage對象image如下:
- private:
- Ui::MainWindow *ui;
- QImage image;
- <span style="font-size:12px;">
- 然後在Mainwindow的構造函數中,對畫布image進行初始化。</span>
- <span style="font-size:12px;">MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- image = QImage(600,300,QImage::Format_RGB32); //畫布的初始化大小設爲600*500,使用32位顏色
- QColor backColor = qRgb(255,255,255); //畫布初始化背景色使用白色
- image.fill(backColor);//對畫布進行填充
- }</span>
這樣,我們就添加好了一塊寬度爲600,高度300的白色畫布。2.3 重載繪畫函數paintEvent
在Mainwindow.h 處添加:
- protected:
- void paintEvent(QPaintEvent *){
- QPainter painter(this);
- painter.drawImage(0,0,image);
- }
表示每當界面有變,便在在(0,0)處開始繪製之前好的image圖像。
運行程序查看效果:
將界面拉大,可以看到存在一片白色區域,這就是我們定義的image的圖像。而外圍的灰色部分爲沒有被覆蓋到的區域。
2.4 利用QPainter在畫布image上繪圖
新建一個Paint函數如下:
- voidMainWindow::Paint()
- {
- QPainter painter(&image);
- painter.setRenderHint(QPainter::Antialiasing, true);//設置反鋸齒模式,好看一點
- int pointx=35,pointy=280;//確定座標軸起點座標,這裏定義(35,280)
- int width=580-pointx,height=260;//確定座標軸寬度跟高度 上文定義畫布爲600X300,寬高依此而定。
- //繪製座標軸 座標軸原點(35,280)
- painter.drawRect(5,5,600-10,300-10);//外圍的矩形,從(5,5)起,到(590,290)結束,周圍留了5的間隙。
- painter.drawLine(pointx,pointy,width+pointx,pointy);//座標軸x寬度爲width
- painter.drawLine(pointx,pointy-height,pointx,pointy);//座標軸y高度爲height
- }
然後在Mainwindow的構造函數中調用(方便起見,實際上哪裏需要畫圖就在哪裏調用)
- MainWindow::MainWindow(QWidget *parent) :
- QMainWindow(parent),
- ui(new Ui::MainWindow)
- {
- ui->setupUi(this);
- image = QImage(600,300,QImage::Format_RGB32); //畫布的初始化大小設爲600*500,使用32位顏色
- QColor backColor = qRgb(255,255,255); //畫布初始化背景色使用白色
- image.fill(backColor);//對畫布進行填充
- Paint();
- }
運行程序,可以看到,此時已經畫出了一個外圍的矩形框,以及未標刻度的x,y軸。注意座標軸原點位於左下方,但是他的座標並不是近似(35,0)而是(35,280)。由於要繪製折線圖,而折線圖的數據量和大小是不確定的,而座標刻度要由此而定,所以暫時先不繪製刻度,而是先處理折線圖數據。
3. 繪製折線圖
3.1 折線圖原理與處理數據
繪製折線圖只要將所有數據對應的點按順序連起來即可。即將(i,a[i])和(i+1,a[i+1])連接。
拿到一組數據,首先找出其最大值和最小值,並將其位置記錄下來。另外還可選擇記錄數據總和、平均值等情況。
這裏採用隨機生成數據的方法爲數組a賦值。
- srand(time(NULL));
- //獲得數據中最大值和最小值、平均數
- int n=30;//n爲數據個數
- double sum=0;
- double ave=0;
- int _ma=0;//數組裏的最大值
- int _mi=inf;//inf爲 #define inf 0x3f3f3f3f
- int a[n];//數據儲存在數組a中,大小爲n
- for(int i=0;i<n;i++)
- a[i]=rand()%40+20;
- int maxpos=0,minpos=0;
- for(int i=0;i<n;i++)
- {
- sum+=a[i];
- if(a[i]>_ma){
- _ma=a[i];
- maxpos=i;
- }
- if(a[i]<_mi){
- _mi=a[i];
- minpos=i;
- }
- }
- ave=sum/n;//平均數
3.2 計算x,y軸比例係數,描點連線
- doublekx=(double)width/(n-1);//x軸的係數
- double ky=(double)height/_ma;//y方向的比例係數
-
- QPen pen,penPoint;
- pen.setColor(Qt::black);
- pen.setWidth(2);
- penPoint.setColor(Qt::blue);
- penPoint.setWidth(5);
-
- for(int i=0;i<n-1;i++)
- {
- //由於y軸是倒着的,所以y軸座標要pointy-a[i]*ky 其中ky爲比例係數
- painter.setPen(pen);//黑色筆用於連線
- painter.drawLine(pointx+kx*i,pointy-a[i]*ky,pointx+kx*(i+1),pointy-a[i+1]*ky);
- painter.setPen(penPoint);//藍色的筆,用於標記各個點
- painter.drawPoint(pointx+kx*i,pointy-a[i]*ky);
- }
-
- 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 畫上平均值,標記上最大值和最小值
- //繪製平均線
- QPen penAve;
- penAve.setColor(Qt::red);//選擇紅色
- penAve.setWidth(2);
- penAve.setStyle(Qt::DotLine);//線條類型爲虛線
- painter.setPen(penAve);
- painter.drawLine(pointx,pointy-ave*ky,pointx+width,pointy-ave*ky);
-
- //繪製最大值和最小值
- QPen penMaxMin;
- penMaxMin.setColor(Qt::darkGreen);//暗綠色
- painter.setPen(penMaxMin);
- painter.drawText(pointx+kx*maxpos-kx,pointy-a[maxpos]*ky-5,
- "最大值"+QString::number(_ma));
- painter.drawText(pointx+kx*minpos-kx,pointy-a[minpos]*ky+15,
- "最小值"+QString::number(_mi));
- penMaxMin.setColor(Qt::red);
- penMaxMin.setWidth(7);
- painter.setPen(penMaxMin);
-
- painter.drawPoint(pointx+kx*maxpos,pointy-a[maxpos]*ky);//標記最大值點
- painter.drawPoint(pointx+kx*minpos,pointy-a[minpos]*ky);//標記最小值點
4. 根據數據爲座標軸添加刻度
- //繪製刻度線
-
- QPen penDegree;
- penDegree.setColor(Qt::black);
- penDegree.setWidth(2);
- painter.setPen(penDegree);
-
- //畫上x軸刻度線
- for(int i=0;i<10;i++)//分成10份
- {
- //選取合適的座標,繪製一段長度爲4的直線,用於表示刻度
- painter.drawLine(pointx+(i+1)*width/10,pointy,pointx+(i+1)*width/10,pointy+4);
- painter.drawText(pointx+(i+0.65)*width/10,
- pointy+10,QString::number((int)((i+1)*((double)n/10))));
- }
-
- //y軸刻度線
- double _maStep=(double)_ma/10;//y軸刻度間隔需根據最大值來表示
- for(int i=0;i<10;i++)
- {
- //主要就是確定一個位置,然後畫一條短短的直線表示刻度。
- painter.drawLine(pointx,pointy-(i+1)*height/10,
- pointx-4,pointy-(i+1)*height/10);
- painter.drawText(pointx-20,pointy-(i+0.85)*height/10,
- QString::number((int)(_maStep*(i+1))));
- }
-
刻度的間隔可自由掌控,比如:
double ky=(double)length*0.4/(_ma-_mi);//y方向的比例係數
等...
至此,一個簡易的QT座標系和折線圖就繪製完成了
源碼可在此處下載
鏈接:http://pan.baidu.com/s/1hqkyVEc 密碼:a58k