如何重新绘制 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 性能。但是,如果您不想抽取,则由您决定。在这种情况下,您可能会考虑一种比 QueuedConnection
ed 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++;
}
我想知道如何在添加新点到 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 性能。但是,如果您不想抽取,则由您决定。在这种情况下,您可能会考虑一种比 QueuedConnection
ed 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++;
}