6

I'd like to know how to repaint a QChart after I append new points to the QLineSeries added to it. The goal is to use this for displaying data being acquired at high rates (up to 400 000 pts/sec) and updating the plot as the points arrive in packets.

Here's the test program I've been working on:

MainWindow:

class MainWindow : public QMainWindow{
    Q_OBJECT

    QLineSeries *series;
    QChart *chart;
    QChartView *chartView;

    int cnt=0;


public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pB_Start_clicked();

private:
    Ui::MainWindow *ui;
};

MainWindow constructor:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){
    ui->setupUi(this);

    series = new QLineSeries();

    chart = new QChart();
    chart->setBackgroundRoundness(0);

    chart->addSeries(series);

 // A bunch of formatting
    chart->setBackgroundVisible(false);
    chart->setMargins(QMargins(0,0,0,0));
    chart->layout()->setContentsMargins(0,0,0,0);
    chart->legend()->hide();
    chart->setPlotAreaBackgroundBrush(QBrush(Qt::black));
    chart->setPlotAreaBackgroundVisible(true);
    chartView = new QChartView(chart);
    ui->gridLayout->addWidget(chartView);

}

And a pushButton clicked event to add points to the series:

void MainWindow::on_pB_Start_clicked(){
    series->append(cnt,qSin(cnt/10));
    cnt++;
    // Update plot here << ======== HOW?
}

The OpenGLSeries example does it somehow. I don't understand how. But that case it's a bit different as it replaces all points in the series with new ones, instead of appending them.

4

2 回答 2

4

显然 QCharts 不需要repaint(). 在该系列中添加新点似乎就足够了。我没有看到数据,因为我没有为 char 设置轴,也因为没有正确计算值。

更正的代码:

标题:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow){
    ui->setupUi(this);

    series = new QLineSeries();

    chart = new QChart();    
    chart->addSeries(series);

    chart->createDefaultAxes(); // Preparing the axis
    chart->axisX()->setRange(0,10); 
    chart->axisY()->setRange(0,10); 

    // Same formatting
    chart->setBackgroundVisible(false);
    chart->setMargins(QMargins(0,0,0,0));
    chart->layout()->setContentsMargins(0,0,0,0);
    chart->legend()->hide();
    chart->setPlotAreaBackgroundBrush(QBrush(Qt::black));
    chart->setPlotAreaBackgroundVisible(true);
    chartView = new QChartView(chart);
    ui->gridLayout->addWidget(chartView);
}

和 pushButton 代码,cnt在计算之前转换为 double。

void MainWindow::on_pB_Start_clicked(){
    double val = 3*(qSin((double)cnt*2)+2);
    series->append(cnt,val); // Enough to trigger repaint!
    cnt++;
}
于 2016-08-06T16:32:21.577 回答
2

首先,如果您将在 GUI 线程中以 400000 点/秒的速度接收和附加点,您的应用程序将完全冻结。因此,您需要将另一个线程专门用于数据接收和处理,并使用(例如)与QueuedConnection连接的信号/插槽将处理后的图形数据发送到 GUI 线程。“处理”是指至少某种抽取(那些 DSP 人员理解的平均、丢弃、抽取),因为 400000 点/秒似乎很快,你会浪费你的内存和 GUI 性能。但是,如果您不想抽取,这取决于您。在这种情况下,您可能会考虑比QueuedConnectioned 信号/插槽更轻量级的数据传递机制。

第二个问题是什么时候绘制?不久前,我QCustomPlot以低得多的速率实现了类似的功能。我面临的主要问题是,当我在收到每个点后尝试重新绘制时,尤其是在绘制抗锯齿图时,会出现巨大(且变化不定)的滞后。在您的情况下,解决方案是子类化QChartView(我想您已经完成了),在其中覆盖并在需要开始/停止重新绘制时timerEvent调用startTimer()/ 。killTimer()或者,您可以在拥有该对象的对象中保存一个计时器QChartView并从那里发出重新绘制,但与子类化相比,它看起来像抽象泄漏QChartView。总而言之,这种方法可以让您实现几乎恒定的帧速率,并使其尽可能流畅,而不会冻结应用程序的界面。

最后,如何重新绘制?QChartView似乎repaint()继承QWidget了您需要的方法。

于 2016-08-06T14:24:04.733 回答