源码下载
replot() 这个函数的作用是用于刷新显示界面,根据文档显示,刷新的方式总共有 4 中:
rpImmediateRefresh 立即全局更新(先立即重绘表格,然后调用 QWidget::repaint() 重绘整个 widget
rpQueuedRefresh 依次更新(先立即重绘表格,然后调用 QWidget::update() 进行更新,避免多次 repaint() 消耗资源)
rpRefreshHint (默认)取决于 hint 是否被设置为 QCP::phImmediaRefresh,可以查看 setPlottingHints)
rpQueuedReplot 整个更新事件循环进行,以避免没有意义的重复更新
所以在作者使用中,采用 300ms 执行一次 replot(QCustomPlot::RefreshPriority::rpQueuedReplot) 进行界面更新
在测试中,IMX6UL, 500M CPU 资源占用率(不是特别高,没有单独计算仅在个人写的APP上为40-50之间波动)
似乎没有找到单独可以调用的函数,所以使用 setData() 函数代替
void clear_all()
{
//getPlot() 就是用来获取 QCustomPlot 指针
getPlot()->graph(0)->setData(QVector(), QVector());
getPlot()->replot();
}
void append_data(const double& key, const double& val)
{
getPlot()->graph(0)->addData(key, val);
}
提供了在 QML 上绘制的 QPainter API,可以将 QWidget 或者自定义控件绘制到 QML 界面上,需要实现 paint() , 如果需要在控件上实现其他功能,比如鼠标功能,可以具体查看 QQuickItem 类中的虚拟函数定义
//ProFile
#需要添加
QT += quick qml printsupport core
//main.cpp
QApplication app(argc, argv); //使用这个来代替 QCoreApplication 等默认创建的 application
qmlRegisterType ("DataModel", 1, 0, "ChartModel_Test");
//main.qml
注意使用 ApplicationWindow{} 来代替 Window()
// qcustomchart.h
#include
class QCustomPlot;
class QCPAbstractPlottable;
class QCustomChart : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit QCustomChart(QQuickItem *parent = nullptr);
virtual ~QCustomChart();
void paint(QPainter *painter) override;
virtual void initChartUI(){};
QCustomPlot *getPlot();
protected:
virtual void mousePressEvent( QMouseEvent* event ) override;
virtual void mouseReleaseEvent( QMouseEvent* event ) override;
virtual void mouseMoveEvent( QMouseEvent* event ) override;
virtual void mouseDoubleClickEvent( QMouseEvent* event ) override;
virtual void wheelEvent( QWheelEvent *event ) override;
void routeMouseEvents( QMouseEvent* event );
void routeWheelEvents( QWheelEvent* event );
public slots:
void onChartViewReplot();
void updateChartViewSize();
private:
QCustomPlot* mCustomPlot {nullptr};
};
//qcustomchart.cpp
#include "qcustomchart.h"
#include "qcustomplot.h"
#include
QCustomChart::QCustomChart(QQuickItem *parent) : QQuickPaintedItem(parent),
mCustomPlot(new QCustomPlot())
{
setFlag(QQuickItem::ItemHasContents, true);
setAcceptedMouseButtons(Qt::AllButtons);
setAcceptHoverEvents(true);
connect(this, &QQuickPaintedItem::widthChanged, this, &QCustomChart::updateChartViewSize);
connect(this, &QQuickPaintedItem::heightChanged, this, &QCustomChart::updateChartViewSize);
}
QCustomChart::~QCustomChart()
{
delete mCustomPlot;
}
void QCustomChart::paint(QPainter *painter)
{
/// add active check
if (!painter->isActive())
return;
QPixmap picture( boundingRect().size().toSize() );
QCPPainter qcpPainter( &picture );
mCustomPlot->toPainter(&qcpPainter);
painter->drawPixmap(QPoint(), picture);
}
QCustomPlot *QCustomChart::getPlot()
{
return mCustomPlot;
}
void QCustomChart::mousePressEvent(QMouseEvent *event)
{
routeMouseEvents(event);
}
void QCustomChart::mouseReleaseEvent(QMouseEvent *event)
{
routeMouseEvents(event);
}
void QCustomChart::mouseMoveEvent(QMouseEvent *event)
{
routeMouseEvents(event);
}
void QCustomChart::mouseDoubleClickEvent(QMouseEvent *event)
{
routeMouseEvents(event);
}
void QCustomChart::wheelEvent(QWheelEvent *event)
{
routeWheelEvents( event );
}
void QCustomChart::updateChartViewSize()
{
mCustomPlot->setGeometry(0, 0, (int)width(), (int)height());
mCustomPlot->setViewport(QRect(0, 0, (int)width(), (int)height()));
}
void QCustomChart::onChartViewReplot()
{
update();
}
void QCustomChart::routeMouseEvents(QMouseEvent *event)
{
QMouseEvent* newEvent = new QMouseEvent(event->type(), event->localPos(), event->button(), event->buttons(), event->modifiers());
QCoreApplication::postEvent(mCustomPlot, newEvent);
}
void QCustomChart::routeWheelEvents(QWheelEvent *event)
{
QWheelEvent* newEvent = new QWheelEvent(event->pos(), event->delta(), event->buttons(), event->modifiers(), event->orientation());
QCoreApplication::postEvent(mCustomPlot, newEvent);
}
//qcustomline.h
#include "qcustomchart.h"
class QCustomLine : public QCustomChart
{
Q_OBJECT
public:
explicit QCustomLine(QQuickItem *parent = nullptr);
virtual ~QCustomLine();
Q_INVOKABLE void initChart();
Q_INVOKABLE void appendData(const double &key, const double &value);
Q_INVOKABLE void replace(const QVector &keys, const QVector &values);
Q_INVOKABLE void clearAll();
Q_INVOKABLE void setXYRange(int x_s, int x_e, int y_s, int y_e);
virtual void timerEvent(QTimerEvent *event) override;
Q_INVOKABLE void append_test();
Q_INVOKABLE void replace_test();
Q_INVOKABLE void updateUI();
};
//qcustomline.cpp
#include "qcustomline.h"
#include "qcustomplot.h"
QCustomLine::QCustomLine(QQuickItem *parent) : QCustomChart(parent)
{
}
QCustomLine::~QCustomLine()
{
}
void QCustomLine::initChart()
{
updateChartViewSize();
getPlot()->addGraph();
getPlot()->graph(0)->setPen( QPen(Qt::red));
getPlot()->xAxis->setLabel( "t1" );
getPlot()->yAxis->setLabel( "S1" );
getPlot()->xAxis->setRange( 0, 1000 );
getPlot()->yAxis->setRange( 0, 10 );
getPlot()->setInteractions( QCP::iRangeDrag | QCP::iRangeZoom );
startTimer(1000);
connect(getPlot(), &QCustomPlot::afterReplot, this, &QCustomLine::onChartViewReplot);
// getPlot()->replot();
}
void QCustomLine::appendData(const double &key, const double &value)
{
getPlot()->graph(0)->addData(key, value);
}
void QCustomLine::replace(const QVector &keys, const QVector &values)
{
getPlot()->graph(0)->setData(keys, values);
getPlot()->replot();
}
void QCustomLine::clearAll()
{
getPlot()->graph(0)->setData(QVector(), QVector());
getPlot()->replot();
}
void QCustomLine::setXYRange(int x_s, int x_e, int y_s, int y_e)
{
getPlot()->xAxis->setRange(x_s, x_e);
getPlot()->yAxis->setRange(y_s, y_e);
getPlot()->replot();
}
void QCustomLine::timerEvent(QTimerEvent */*event*/)
{
static double t, U;
U = ((double)rand() / RAND_MAX) * 5;
getPlot()->graph(0)->addData(t++, U);
getPlot()->replot();
}
void QCustomLine::append_test()
{
static double t, U;
U = ((double)rand() / RAND_MAX) * 5;
appendData(t++, U);
}
void QCustomLine::replace_test()
{
QVector tX;
QVector tY;
tX << 1 << 3 << 4;
tY << 1 << 5 << 1;
replace(tX, tY);
}
void QCustomLine::updateUI()
{
getPlot()->replot(QCustomPlot::RefreshPriority::rpQueuedReplot);
}
如果出现这种异常提示:
QPainter::begin: Paint device returned engine = 0, type: 2
QPainter::setRenderHint: Painter must be active to set rendering hints
请检查,
一:QML 是否已经用 ApplicationWindow 代替 Window 控件
二:在使用中,作者是通过 loader 加载的控件,并且在启动之后默认调用了 replot() 根本原因在于时间差,paint device 并没有准备好,所以可以略微延时执行,在构造函数中不要调用 replot()
很有可能是由于过快过多的图表刷新导致,内存资源耗尽导致程序嗝屁,建议跟新界面刷新策略,比如降低界面刷新的频率,去掉没有意义的界面刷新步骤