Qt绘制曲线图(基于qt画图QPainter)

3 篇文章 0 订阅
该代码示例展示了如何在没有QChart模块的情况下,利用QPainter和QImage在Qt环境中手动生成曲线折线图。通过创建QLabel并设置QPixmap显示自定义绘制的图像,实现了数据的图形化展示。代码中包括了坐标轴、刻度、数据点和曲线的绘制方法。
摘要由CSDN通过智能技术生成

在没有QCharst模块时,可以使用QPainter自定义绘制曲线折线图

在这里插入图片描述
下面提供完整代码供参考:
直接在qt创建一个QMainWindow类的app的工程,不自动生成ui文件,然后把下面代码复制到mainwindow.cpp编译运行即可。
mainwindow.cpp:

#include "mainwindow.h"

#include <QPainter>
#include <QLabel>
#include <QImage>
#include <QPixmap>

//使用QPainter将数据到曲线画在图片中
QImage imageCurve(const QVector<int> &data1, const QVector<int> &data2);

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(800,600);

    int n=10;//n为数据个数
    QVector<int> data1;
    QVector<int> data2;

    for(int i=0;i<n;i++)//随机产生两个数据集
        data1.append(rand()%20+10);
    for(int i=0;i<n;i++)
        data2.append(rand()%30+10);

    QLabel *label = new QLabel(this);

    label->setGeometry(50,50,600,500);//将画出来到曲线显示到label上面
    label->setPixmap(QPixmap::fromImage(imageCurve(data1,data2)));
    label->show();
}

MainWindow::~MainWindow()
{

}


QImage imageCurve(const QVector<int> &data1, const QVector<int> &data2)
{
    QString x_title = "x_title";//x坐标名称
    QString y_title = "y_title";//y坐标名称
    QString title = "xx title charst";//曲线图xx名称
    QString overView = "charst: test,csdn: boonion";//图内容说明

    QString data1_name = "first";//第一条曲线名称
    QString data2_name = "second";


    QImage mimage = QImage(600,500,QImage::Format_RGB32);  //画布的初始化大小设为600*500,使用32位颜色
    QColor backColor = qRgb(255,255,255);    //画布初始化背景色使用白色
    mimage.fill(backColor);//对画布进行填充

    QPainter painter(&mimage);

    painter.setRenderHint(QPainter::Antialiasing, true);//设置反锯齿模式,好看一点


    int pointx=30,pointy=420;//确定坐标轴起点坐标,这里定义(35,280)
    int width=560-pointx,height=280;//确定坐标轴宽度跟高度


    painter.drawLine(pointx,pointy,width+pointx,pointy);//坐标轴x宽度为width
    painter.drawLine(pointx,pointy-height,pointx,pointy);//坐标轴y高度为height


    int n=data1.size();//n为第一个数据集个数
    int m = data2.size();

    int max=0;//数组里的最大值

    for(int i = 0 ; i < n; i++)
    {
        if(data1[i] > max)
        {
            max = data1[i];
        }
    }

    for(int i = 0 ; i < m; i++)
    {
        if(data2[i] > max)
        {
            max = data2[i];
        }
    }


    double kx=(double)width/(n-1); //x轴的系数
    double ky=(double)height/max;//y方向的比例系数

    //设置两条的画笔
    QPen pen,penPoint;
    pen.setColor(Qt::green);
    pen.setWidth(2);

    penPoint.setColor(Qt::blue);
    penPoint.setWidth(5);

    QPen penOther,penPointOther;
    penOther.setColor(Qt::yellow);
    penOther.setWidth(2);

    penPointOther.setColor(Qt::red);
    penPointOther.setWidth(5);

    for(int i=0;i<n-1;i++)//画第一条线
    {
        if(i+1 > n-1)
            break;
        //由于y轴是倒着的,所以y轴坐标要pointy-a[i]*ky 其中ky为比例系数
        painter.setPen(pen);//用于连线
        painter.drawLine(pointx+kx*i,pointy-data1[i]*ky,pointx+kx*(i+1),pointy-data1[i+1]*ky);
        painter.setPen(penPoint);//蓝色的笔,用于标记各个点
        painter.drawPoint(pointx+kx*i,pointy-data1[i]*ky);
        painter.drawText(pointx+kx*i,pointy-data1[i]*ky-4,
                         QString::number(data1[i]));
    }
    if(!data1.isEmpty())
        painter.drawPoint(pointx+kx*(n-1),pointy-data1[n-1]*ky);//绘制最后一个点

    //画线图示
    painter.setPen(pen);
    painter.drawLine(pointx+width-50,pointy-height-50,pointx+width-25,pointy-height-50);
    painter.setPen(penPoint);
    painter.drawPoint(pointx+width-25,pointy-height-50);
    painter.setPen(pen);
    painter.drawLine(pointx+width-20,pointy-height-50,pointx+width,pointy-height-50);
    painter.setPen(Qt::black);
    painter.drawText(pointx+width-40,pointy-height-30,QString("%1").arg(data1_name));


    for(int i=0;i<m-1;i++)
    {
        if(i+1 > m-1)
            break;

        painter.setPen(penOther);
        painter.drawLine(pointx+kx*i,pointy-data2[i]*ky,pointx+kx*(i+1),pointy-data2[i+1]*ky);
        painter.setPen(penPointOther);
        painter.drawPoint(pointx+kx*i,pointy-data2[i]*ky);
        painter.drawText(pointx+kx*i,pointy-data2[i]*ky-5,
                         QString::number(data2[i]));
    }
    if(!data2.isEmpty())
         painter.drawPoint(pointx+kx*(m-1),pointy-data2[m-1]*ky);//绘制最后一个点

    //画线图示
    painter.setPen(penOther);
    painter.drawLine(pointx+width-50,pointy-height-100,pointx+width-25,pointy-height-100);
    painter.setPen(penPointOther);
    painter.drawPoint(pointx+width-25,pointy-height-100);
    painter.setPen(penOther);
    painter.drawLine(pointx+width-20,pointy-height-100,pointx+width,pointy-height-100);
    painter.setPen(Qt::black);
    painter.drawText(pointx+width-40,pointy-height-80,QString("%1").arg(data2_name));


    //绘制刻度线
    int tmp = n > m ? n : m; //取刻度最大的分度值
    int xn = tmp > 16 ? 16 : tmp;

    int yn = max > 20 ? 20 : max;


    QPen penDegree;
    penDegree.setColor(Qt::black);
    penDegree.setWidth(2);
    painter.setPen(penDegree);

    //画上x轴刻度线
    for(int i=0;i<xn;i++)//分成dn份
    {
        //选取合适的坐标,绘制一段长度为4的直线,用于表示刻度

        painter.drawLine(pointx+(i+1)*width/xn,pointy,pointx+(i+1)*width/xn,pointy+4);
        painter.drawText(pointx+(i)*width/xn,
                         pointy+15,QString::number((int)((i)*((double)tmp/xn))));
    }

    //画xy刻度名称
    painter.setPen(Qt::black);
    painter.drawText(pointx+width-40,pointy+30,QString("%1").arg(x_title));
    painter.setPen(Qt::black);
    painter.drawText(pointx-10,pointy-height-30,QString("%1").arg(y_title));


    //y轴刻度线
    double _maStep=(double)max/yn;//y轴刻度间隔需根据最大值来表示
    for(int i=0;i<yn;i++)
    {

        //主要就是确定一个位置,然后画一条短短的直线表示刻度。
        painter.drawLine(pointx,pointy-(i+1)*height/yn,
                         pointx-4,pointy-(i+1)*height/yn);
        painter.drawText(pointx-20,pointy-(i+0.85)*height/yn,
                         QString::number((int)(_maStep*(i+1))));
    }


    //画图内容说明
    QStringList strlist = overView.split(',');//分割字符串
    painter.setPen(Qt::gray);

    int t_h = 100;

    foreach(QString str,strlist)
    {
      painter.drawText(pointx+40,pointy-height-t_h,QString("%1").arg(str));
      t_h -= 20;

    }


    //画标题
    painter.setPen(Qt::black);
    QFont font;
    font.setPixelSize(20);
    painter.setFont(font);
    painter.drawText(pointx+width/2-80,pointy-height-60,QString("%1").arg(title));

    return mimage;
}
//博客:booinon
//https://blog.csdn.net/boonion?spm=1011.2415.3001.5343

//博客:booinon
//https://blog.csdn.net/boonion?spm=1011.2415.3001.5343

折线图的显示需要使用Qt中的QChart和QChartView类,同时还需要使用QLineSeries、QValueAxis和QCategoryAxis等类来设置折线数据和坐标轴等信息。下面是一个简单的用Python编写的显示折线图的例子: ```python from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout from PyQt5.QtChart import QChart, QChartView, QLineSeries, QValueAxis, QCategoryAxis class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("折线图示例") self.setGeometry(100, 100, 800, 600) # 创建QWidget作为主窗口的中心区域 central_widget = QWidget(self) self.setCentralWidget(central_widget) # 创建折线图 chart = QChart() chart.setTitle("折线图示例") chart.setAnimationOptions(QChart.AllAnimations) # 设置X轴和Y轴 axis_x = QCategoryAxis() axis_x.append("1", 1) axis_x.append("2", 2) axis_x.append("3", 3) axis_x.append("4", 4) axis_x.append("5", 5) axis_x.setTitleText("X轴") axis_y = QValueAxis() axis_y.setRange(0, 10) axis_y.setTitleText("Y轴") chart.addAxis(axis_x, Qt.AlignBottom) chart.addAxis(axis_y, Qt.AlignLeft) # 添加折线数据 series = QLineSeries() series.append(1, 4) series.append(2, 5) series.append(3, 6) series.append(4, 7) series.append(5, 8) chart.addSeries(series) series.attachAxis(axis_x) series.attachAxis(axis_y) # 创建QChartView并将其设置为中心窗口 chart_view = QChartView(chart) chart_view.setRenderHint(QPainter.Antialiasing) layout = QVBoxLayout(central_widget) layout.addWidget(chart_view) if __name__ == '__main__': app = QApplication([]) window = MainWindow() window.show() app.exec_() ``` 运行代码后会显示一个窗口,其中包含一个折线图,如下图所示: ![折线图示例](https://cdn.jsdelivr.net/gh/krislinzhao/Storage_Space/blog_images/pyqt5_chart.png)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

boonion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值