qt 折线图开发

来源:互联网 发布:js innerhtml赋值 编辑:程序博客网 时间:2024/05/20 10:23

1. QT坐标系统。

在画坐标系之前,我们得先了解一下QT5的坐标系统。

QT5的坐标设定左上角为原点(0,0),向右为x轴正方向,向下为y轴正方向,这点与生活中常见的直角坐标系不同。



2. 绘制直角坐标系

    2.1 添加头文件

     #include<QPaintEvent> //用于绘画事件

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

   

    2.2  添加画布

    我们选择在一个画布上进行绘画。

    在mainwindow.h处添加一个QImage对象image如下:

[cpp] view plain copy print?
  1. private:  
  2.     Ui::MainWindow *ui;  
  3.     QImage image;  
[cpp] view plain copy print?
  1. <span style="font-size:12px;">   
  2. 然后在Mainwindow的构造函数中,对画布image进行初始化。</span>  


[cpp] view plain copy print?
  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 处添加:

[cpp] view plain copy print?
  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函数如下:

[cpp] view plain copy print?
  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的构造函数中调用(方便起见,实际上哪里需要画图就在哪里调用)

[cpp] view plain copy print?
  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赋值。

[cpp] view plain copy print?
  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轴比例系数,描点连线

[cpp] view plain copy print?
  1. doublekx=(double)width/(n-1);//x轴的系数  
  2.     double ky=(double)height/_ma;//y方向的比例系数  
  3.   
  4.     QPen pen,penPoint;  
  5.     pen.setColor(Qt::black);  
  6.     pen.setWidth(2);  
  7.     penPoint.setColor(Qt::blue);  
  8.     penPoint.setWidth(5);  
  9.   
  10.     for(int i=0;i<n-1;i++)  
  11.     {  
  12.         //由于y轴是倒着的,所以y轴坐标要pointy-a[i]*ky 其中ky为比例系数  
  13.         painter.setPen(pen);//黑色笔用于连线  
  14.         painter.drawLine(pointx+kx*i,pointy-a[i]*ky,pointx+kx*(i+1),pointy-a[i+1]*ky);  
  15.         painter.setPen(penPoint);//蓝色的笔,用于标记各个点  
  16.         painter.drawPoint(pointx+kx*i,pointy-a[i]*ky);  
  17.     }  
  18.   
  19.     painter.drawPoint(pointx+kx*(n-1),pointy-a[n-1]*ky);//绘制最后一个点  


把x轴评分给n个数据,所以kx=width/(n-1)(第一个数据在y轴上,所以总共有n-1个间隔)。

这里假设数据均为正数,所以ky这样定义、,如果存在负数,或者只想显示最小值和最大值之间的那一段数据,可以将ky改为

[cpp] view plain copy print?
  1. double ky=(double)/(_ma-_mi);//y方向的比例系数  


如果只想在坐标轴的某一部分显示图像,还可为将ky改为带有length的等等,如:

[cpp] view plain copy print?
  1. double ky=(double)length*0.4/(_ma-_mi);//y方向的比例系数  


3.3 画上平均值,标记上最大值和最小值

[cpp] view plain copy print?
  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.     //绘制最大值和最小值  
  10.     QPen penMaxMin;  
  11.     penMaxMin.setColor(Qt::darkGreen);//暗绿色  
  12.     painter.setPen(penMaxMin);  
  13.     painter.drawText(pointx+kx*maxpos-kx,pointy-a[maxpos]*ky-5,  
  14.                      "最大值"+QString::number(_ma));  
  15.     painter.drawText(pointx+kx*minpos-kx,pointy-a[minpos]*ky+15,  
  16.                      "最小值"+QString::number(_mi));  
  17.     penMaxMin.setColor(Qt::red);  
  18.     penMaxMin.setWidth(7);  
  19.     painter.setPen(penMaxMin);  
  20.   
  21.     painter.drawPoint(pointx+kx*maxpos,pointy-a[maxpos]*ky);//标记最大值点  
  22.     painter.drawPoint(pointx+kx*minpos,pointy-a[minpos]*ky);//标记最小值点  


4. 根据数据为坐标轴添加刻度

[cpp] view plain copy print?
  1. //绘制刻度线  
  2.   
  3.     QPen penDegree;  
  4.     penDegree.setColor(Qt::black);  
  5.     penDegree.setWidth(2);  
  6.     painter.setPen(penDegree);  
  7.   
  8.     //画上x轴刻度线  
  9.     for(int i=0;i<10;i++)//分成10份  
  10.     {  
  11.         //选取合适的坐标,绘制一段长度为4的直线,用于表示刻度  
  12.         painter.drawLine(pointx+(i+1)*width/10,pointy,pointx+(i+1)*width/10,pointy+4);  
  13.         painter.drawText(pointx+(i+0.65)*width/10,  
  14.                          pointy+10,QString::number((int)((i+1)*((double)n/10))));  
  15.     }  
  16.   
  17.     //y轴刻度线  
  18.     double _maStep=(double)_ma/10;//y轴刻度间隔需根据最大值来表示  
  19.     for(int i=0;i<10;i++)  
  20.     {  
  21.         //主要就是确定一个位置,然后画一条短短的直线表示刻度。  
  22.         painter.drawLine(pointx,pointy-(i+1)*height/10,  
  23.                          pointx-4,pointy-(i+1)*height/10);  
  24.         painter.drawText(pointx-20,pointy-(i+0.85)*height/10,  
  25.                          QString::number((int)(_maStep*(i+1))));  
  26.     }  

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

[cpp] view plain copy print?
  1. double ky=(double)length*0.4/(_ma-_mi);//y方向的比例系数  


等...


至此,一个简易的QT坐标系和折线图就绘制完成了奋斗

源码可在此处下载

链接:http://pan.baidu.com/s/1hqkyVEc 密码:a58k



代码来源http://blog.csdn.net/a343902152/article/details/47021781

原创粉丝点击