Qt由入门到放弃-QCustomPlot绘制天气曲线图并动态显示曲线坐标值(二)

       上一篇文章 Qt由入门到放弃-QCustomPlot之QCPAxisTicker坐标轴类 介绍了QCustomPlot的坐标轴类的基本功能和用法,此篇文章在其基础上用实例制作一个简单的天气数据显示界面,基本的代码上篇文章已有,此篇文章的重点放在通过QToolTip控件类来实现天气曲线上的数据随鼠标移动显示的功能,先看一个简单效果图:

一、基本功能代码实现

1. 构造函数的信号与槽函数

      QCustomPlot里面已有mouseMove信号,在这里自定义一下接收槽函数myMoveEvent

connect(customPlot,SIGNAL(mouseMove(QMouseEvent *)),this,SLOT(myMoveEvent(QMouseEvent *)));

2. 槽函数的具体实现

       基本思路是首先通过鼠标移动事件获取鼠标所在的位置;然后转换鼠标位置获取到QCustomPlot空间的坐标系中对应的数据点,其中使用了pixelToCoord()函数---->把ui控件的坐标映射到QCustomPlot数据显示坐标;其次就是使用QToolTip来做数据显示,由于要保证QToolTip的文本框要随曲线移动,实际上需要得到鼠标移动时曲线上的点的坐标,line_y_val 就是对应的曲线y值;最后别忘了使用coordToPixel()函数把QCustomPlot的曲线坐标转成桌面坐标show出QToolTip。

void MainWindow::myMoveEvent(QMouseEvent *event)
{
    //获取鼠标坐标,相对父窗体坐标
    int x_pos = event->pos().x();
    int y_pos = event->pos().y();
    qDebug()<<"event->pos()"<<event->pos();

    //鼠标坐标转化为CustomPlot内部坐标
    float x_val = customPlot->xAxis->pixelToCoord(x_pos);
    float y_val = customPlot->yAxis->pixelToCoord(y_pos);
    //获得x轴坐标位置对应的曲线上y的值
    float line_y_val = customPlot->graph(0)->data()->at(x_val)->value;
    //曲线的上点坐标位置,用来显示QToolTip提示框
    float out_x = customPlot->xAxis->coordToPixel(x_val);
    float out_y = customPlot->yAxis->coordToPixel(line_y_val);

    QString str,strToolTip;
    str = QString::number(x_val,10,3);
    strToolTip += "x: ";
    strToolTip += str;
    strToolTip += "\n";

    str = QString::number(line_y_val,10,3);
    strToolTip += "y: ";
    strToolTip += str;
    strToolTip += "\n";

    QToolTip::showText(mapToGlobal(QPoint(out_x,out_y)),strToolTip,customPlot);

}

 3. 评价

       效果看上去像那么回事,就是太。。。丑了,没办法,c++搞界面你懂得。不过好歹我们还是要继续美化一下,如把坐标轴换成QCPAxisTickerDateTime类,加上单位,控制显示。

二、天气预报的日期时间轴的添加

1. Bug版实现

       在一的基础上我高兴的把x轴坐标换成QCPAxisTickerDateTime加上,初步判断可以实现实时显示特定时间的动态曲线,上代码:

void MainWindow::SlotToTem()
{
    customPlot->setInteraction(QCP::iRangeDrag, true);
    customPlot->setInteraction(QCP::iRangeZoom, true);
    QDateTime dateTime = QDateTime::currentDateTime();
    double  now = dateTime.toTime_t();//当前时间转化为秒
    //生成时间刻度对象
    QSharedPointer<QCPAxisTickerDateTime> dateTimeTicker(new QCPAxisTickerDateTime);
    customPlot->xAxis->setTicker(dateTimeTicker);
    //dateTimeTicker->setDateTimeSpec(Qt::UTC);//设施世界时间,即不加上时区的时间
    dateTimeTicker->setTickCount(24);
    dateTimeTicker->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
    customPlot->xAxis->setSubTicks(false);
    customPlot->xAxis->setRange(now, now+3600*24);//x轴范围,从当前时间起往后推24小时
    QVector<double> yData, xData;//生成数据
    for (int i = 0; i <= 24; i++)
    {
        xData.push_back(now + i * 3600.0);

    }
    yData = {
        22,23,24,25,25.5,26,26.5,27,
        27.5,28,28.5,29,30,31,32,33,
        35,34,33,31,29,27,26,25,
    };
    dateTimeTicker->setDateTimeFormat("yyyy-M-d h:m");//设置x轴刻度显示格式
    customPlot->xAxis->setTickLabelRotation(30);//设置刻度标签顺时针旋转30度
    customPlot->yAxis->setRange(20,40);
    customPlot->graph(0)->setData(xData, yData);//显示数据
    customPlot->xAxis->setLabel("时间");
    customPlot->yAxis->setLabel("温度/摄氏度");
    customPlot->replot();

}

       效果图:时间轴有了,数据却没了(都是自己生成的数据,没有获取在线实时数据)!仔细观察发现x轴显示的秒数,也就是说实际上坐标轴只是填充了24个数据,而QCPAxisTicker坐标轴折线图最小的辨识度为1个整数刻度,我的预期是在 QVector<double> xData的数据间会自动补全缺失yData数据,显然没有达到这个功能要求,只能自己来线性插值补全了(没有找到自导的功能方法,大家有兴趣可以看看源码是否有已经实现的方法)。

2. 线性插值缺失数据(依旧是个BUG)

void MainWindow::SlotToTem()
{
    customPlot->setInteraction(QCP::iRangeDrag, true);
    customPlot->setInteraction(QCP::iRangeZoom, true);
    QDateTime dateTime = QDateTime::currentDateTime();
    int  now = dateTime.toTime_t();//当前时间转化为秒
    qDebug()<<now<<"=============";
    //生成时间刻度对象
    QSharedPointer<QCPAxisTickerDateTime> dateTimeTicker(new QCPAxisTickerDateTime);
    customPlot->xAxis->setTicker(dateTimeTicker);
    dateTimeTicker->setTickCount(24);
    dateTimeTicker->setTickStepStrategy(QCPAxisTicker::tssMeetTickCount);
    customPlot->xAxis->setSubTicks(false);
    customPlot->xAxis->setRange(now, now+3600*24);//x轴范围,从当前时间起往后推24小时
    QVector<double> xData,yData;
    QVector<double> xData1, yData1;//生成数据
    for (int i = 0; i <= 24; i=i+1)
    {
        xData.push_back(now + i * 3600);
    }

    yData = {
        22,23,24,25,25.5,26,26.5,27,
        27.5,28,28.5,29,30,31,32,33,
        35,34,33,31,29,27,26,25,24
    };

    for(int i=0;i<xData.size()-1;i++)
    {
        double startValue = yData.at(i);
        double endValue = yData.at(i+1);
        int temp = now + i*3600;

        for(int j= temp;j< temp + 3600;j++)
        {

            double y_val = startValue + (j - temp) *(endValue - startValue)/3600;
            xData1.push_back(double(j));
            yData1.push_back(y_val );
            //qDebug()<<"===="<<y_val<<"---"<<j;

        }

    }

    dateTimeTicker->setDateTimeFormat("yyyy-M-d h:m");//设置x轴刻度显示格式
    customPlot->xAxis->setTickLabelRotation(30);//设置刻度标签顺时针旋转30度
    customPlot->yAxis->setRange(20,40);
    customPlot->graph(0)->addData(xData1, yData1);//显示数据
    customPlot->xAxis->setLabel("时间");
    customPlot->yAxis->setLabel("温度/摄氏度");
    customPlot->replot();

}

效果图:我们看到还是没有数据显示,不知什么情况。。。。

三、结论

       由我的实验结果来看,对一般的连续数据(数据间隔一个整数单位),可以实现动态的数据显示,对于间隔天气数据本作者无法实现使用QCPAxisTickerDateTime。

      相关代码点我下载,望读者看到此篇文章能给予一定的解答。

  • 13
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值