QML使用QCustomPlot笔记

        这里在QML中使用QCustomPlot是定义一个继承自QQuickPaintedItem的类,它包含一个QCustomPlot对象,在paint函数中将这个对象转化为pixmap绘制到布局中显示。

在QML中使用QT的Widget控件也可以借鉴这个思路实现

顺便记录一下QCustomPlot的简单设置与使用。

QCustomPlot可以直接到官网下载源码。

main.cpp中添加代码,将C++类注册为QML组件

#include "plot/liquidheightplot.h"
...

int main(int argc, char *argv[])
{
...
    qmlRegisterType("LiquidHeightPlot", 1, 0, "LiquidHeightPlot");
...
}

类定义liquidheightplot.h

#ifndef LIQUIDHEIGHTPLOT_H
#define LIQUIDHEIGHTPLOT_H

#include "qcustomplot/qcustomplot.h"
#include 
#include 
#include 
#include 

class LiquidHeightPlot : public QQuickPaintedItem
{
    Q_OBJECT
public:
    explicit LiquidHeightPlot(QQuickItem *parent = nullptr);
    ~LiquidHeightPlot();

    //更新实时数据
    Q_INVOKABLE void updateRealData(double value);

    //设置历史数据
    Q_INVOKABLE void setHistoryData(QJsonObject data);

    //清除数据
    Q_INVOKABLE void clearData();


signals:
    void sigIllegalData();

private:
    virtual void paint(QPainter *painter);

private:
    QCustomPlot *m_customPlot;
    double                  m_maxY;
    QVector         m_x1;
    QVector         m_y1;
};

#endif // LIQUIDHEIGHTPLOT_H

类实现liquidheightplot.cpp

#include "liquidheightplot.h"
#include 
#include 

LiquidHeightPlot::LiquidHeightPlot(QQuickItem *parent)
    : QQuickPaintedItem(parent)
    , m_customPlot(nullptr)
{
    m_customPlot = new QCustomPlot();
    m_customPlot->rescaleAxes(true);

    //设置轴 ============================
    QFont font;
    font.setPixelSize(16);
    m_customPlot->xAxis->setLabelFont(font);
    m_customPlot->yAxis->setLabelFont(font);
    m_customPlot->xAxis->setLabel(tr("时间"));
    m_customPlot->yAxis->setLabel(tr("液位高度(cm)"));
    m_customPlot->xAxis->setLabelColor(QColor(Qt::gray));//轴标体色
    m_customPlot->yAxis->setLabelColor(QColor(Qt::gray));
    m_customPlot->xAxis->setBasePen(QPen(QColor(Qt::gray), 1));//轴色
    m_customPlot->yAxis->setBasePen(QPen(QColor(Qt::gray), 1));
    m_customPlot->xAxis->setTickPen(QPen(QColor(Qt::gray), 1));//轴主标色
    m_customPlot->yAxis->setTickPen(QPen(QColor(Qt::gray), 1));
    m_customPlot->xAxis->setSubTickPen(QPen(QColor(Qt::gray), 1));//轴次标色
    m_customPlot->yAxis->setSubTickPen(QPen(QColor(Qt::gray), 1));
    font.setPixelSize(14);
    m_customPlot->xAxis->setTickLabelFont(font);
    m_customPlot->yAxis->setTickLabelFont(font);
    m_customPlot->xAxis->setTickLabelColor(QColor(Qt::gray));//轴标文本色
    m_customPlot->yAxis->setTickLabelColor(QColor(Qt::gray));
    m_customPlot->setBackground(QBrush(QColor(Qt::white)));
    m_customPlot->setGeometry(0, 0, width()*1.6, height()*1.6);
    m_customPlot->setMultiSelectModifier(Qt::KeyboardModifier::ControlModifier);
    //设置边距
    QCPMarginGroup *marginGroup = new QCPMarginGroup(m_customPlot);
    m_customPlot->plotLayout()->setMargins(QMargins(0, 0, 0, 0));
    m_customPlot->axisRect()->setMarginGroup(QCP::msLeft | QCP::msRight | QCP::msTop | QCP::msBottom, marginGroup);
    //设置时间轴
    QSharedPointer dateTicker(new QCPAxisTickerDateTime);
    dateTicker->setDateTimeFormat("yyyyMMdd\nhh:mm");
    m_customPlot->xAxis->setTicker(dateTicker);
    QString sCurrent = QDateTime::currentDateTime().toString("yyyyMMdd hh:00:00");
    QDateTime current = QDateTime::fromString(sCurrent, "yyyyMMdd hh:mm:ss");
    m_customPlot->xAxis->setRange(current.toTime_t(), current.toTime_t() + 1800);//默认显示时间轴当前半小时
    //纵轴
    QSharedPointer ticker(new QCPAxisTicker);
    m_customPlot->yAxis->setTicker(ticker);
    m_customPlot->yAxis->setRange(0, 200);
    //添加数据曲线图形
    m_customPlot->addGraph();
    m_customPlot->graph(0)->setPen(QPen(Qt::blue));
    //显示图例
    QCPLegend * legend = m_customPlot->legend;
    m_customPlot->legend->setVisible(true);
    legend->setFont(font);
    legend->setBrush(QColor(Qt::gray));
    legend->setTextColor(QColor(Qt::white));
    m_customPlot->graph(0)->setName("液位曲线");//设置

    clearData();
}

LiquidHeightPlot::~LiquidHeightPlot()
{
    m_customPlot->deleteLater();
    m_customPlot = nullptr;
}

void LiquidHeightPlot::paint(QPainter *painter)
{
    m_customPlot->setGeometry(0,0,this->width()*1.6,this->height()*1.6);
    painter->drawPixmap(0,0,this->width(),this->height(), m_customPlot->toPixmap());
}

//更新实时数据
void LiquidHeightPlot::updateRealData(double value)
{
    QDateTime current = QDateTime::currentDateTime();
    if(m_x1.size() == 0) {//第一帧实时数据
        m_customPlot->xAxis->setRange(current.toTime_t(), current.toTime_t() + 1800);
    }
    if(m_x1.size() > 0 && m_x1.last() == current.toTime_t()) return;//同一时间的数据
    while (m_x1.size() >= 30) {//半小时,30个数据
        m_x1.takeFirst();
        m_y1.takeFirst();
    }
    m_x1.push_back(current.toTime_t());
    m_y1.push_back(value);
    if(m_maxY < value) {//更新最大值
        m_maxY = value;
        m_maxY = (m_maxY / 10 + 1) * 10;
        m_customPlot->yAxis->setRange(0, m_maxY);
    }
    if(m_x1.size() == 30) m_customPlot->xAxis->setRange(m_x1.first(), m_x1.last());//更新轴
    m_customPlot->graph(0)->setData(m_x1, m_y1);
    m_customPlot->replot();//刷新曲线
    update();//刷新显示
}

//设置历史数据
//"data": {
//    "maxLiquidLevelHeight": "68,88",
//    "minLiquidLevelHeight": "68,88",
//    "time": "2023-01-02 22:59:59,2023-01-02 23:59:59",
//  }
void LiquidHeightPlot::setHistoryData(QJsonObject data)
{
    QString maxLiquidLevelHeight = data["maxLiquidLevelHeight"].toString();
    QString times = data["time"].toString();
    maxLiquidLevelHeight.remove('\n');
    times.remove('\n');
    QStringList heightList = maxLiquidLevelHeight.split(",", QString::SkipEmptyParts);
    QStringList timeList = times.split(",", QString::SkipEmptyParts);
    if (heightList.count() != timeList.count()) {
        qDebug() << "LiquidHeightPlot::setHistoryData error heightList.count() != timeList.count() !";
        return;
    }
    for (int i = 0; i < heightList.count(); i++) {
        QDateTime time = QDateTime::fromString(timeList[i], "yyyy-MM-dd HH:mm:ss");
        qDebug() << "LiquidHeightPlot::setHistoryData time isValid " << time.isValid() << time;
        if(!time.isValid()) {//存在非法数据
            emit sigIllegalData();
            return;
        }
        uint value = heightList[i].toInt();
        m_x1.append(time.toTime_t());
        m_y1.append(value);
        if(m_maxY < value) {//更新最大值
            m_maxY = value;
            m_maxY = (m_maxY / 10 + 1) * 10;
            m_customPlot->yAxis->setRange(0, m_maxY);
        }
    }
    m_customPlot->xAxis->setRange(m_x1.first(), m_x1.last());
    m_customPlot->graph(0)->setData(m_x1, m_y1);
    m_customPlot->replot();//刷新曲线
    update();//刷新显示
    qDebug() << "LiquidHeightPlot::setHistoryData m_x1" << m_x1 << ",\n m_y1" << m_y1;
}

//清除数据
void LiquidHeightPlot::clearData()
{
    qDebug() << "LiquidHeightPlot::clearData ---------------------------------";
    m_maxY = 200;
    m_x1.clear();
    m_y1.clear();
    m_customPlot->graph(0)->setData(m_x1, m_y1);
    m_customPlot->replot();//刷新曲线
    update();//刷新显示
}

QML的使用

import LiquidHeightPlot 1.0

Item {
    id: root
...
        LiquidHeightPlot {
            id: liquidHeightPlot
            anchors.fill: parent
            onSigIllegalData: {
                popuTip.text = qsTr("数据异常 !");
                popuTip.visible = true;
            }
        }
...
}

你可能感兴趣的:(QT,笔记,qt5,c++)