如何重新绘制 QChart

How to repaint a QChart

我想知道如何在添加新点到 QLineSeries 后重新绘制 QChart 目标是使用它来显示以高速率(高达 400 000 pts/sec)获取的数据,并在点以数据包形式到达时更新绘图。

这是我一直在做的测试程序:

主窗口:

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::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);

}

还有一个按钮 clicked 事件来为系列添加点数:

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

OpenGLSeries 示例以某种方式做到了这一点。我不明白怎么办。但这种情况有点不同,因为它用新点替换了系列中的所有点,而不是附加它们。

首先,如果您将在 GUI 线程中接收并追加 400000 pts/sec 点,您的应用程序将完全冻结。所以需要专门另外一个线程进行数据的接收和处理,将处理后的图形数据发送给GUI线程使用(例如)signals/slots连接QueuedConnection。 "processing" 我的意思是至少某种抽取(平均、下降、抽取,正如那些 DSP 人员所理解的那样),因为 400000 pts/sec 似乎很快,你会浪费你的内存和 GUI 性能。但是,如果您不想抽取,则由您决定。在这种情况下,您可能会考虑一种比 QueuedConnectioned signals/slots 更轻量级的数据传输机制。

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

最后,如何重绘? QChartView 似乎有 repaint() 继承自 QWidget 的方法,它可以满足您的需要。

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

更正后的代码:

Header:

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);
}

和按钮代码,在计算之前将 cnt 转换为两倍。

void MainWindow::on_pB_Start_clicked(){
    double val = 3*(qSin((double)cnt*2)+2);
    series->append(cnt,val); // Enough to trigger repaint!
    cnt++;
}