[英]How to update QCustomPlot Data in thread?
我想在c ++中顯示QCustomPlot的實時數據。 所以我這樣做:
在頭文件中:
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
private:
Ui::QtGuiApplicationClass ui;
//plot
QCustomPlot* plot_;
std::thread thread_Displayer_;
bool thread_run_flag_ = false;
void thread_Displayer_fn();
};
在源文件中,我使用按鈕啟動線程,並...像這樣:
void QtGuiApplication::btn_Display_clicked()
{
if (thread_run_flag_)
{
ui.btn_Dispaly->setText("Display");
thread_run_flag_ = false;
if (thread_Displayer_.joinable())
{
thread_Displayer_.join();
}
}
else
{
thread_run_flag_ = false;
if (thread_Displayer_.joinable())
{
thread_Displayer_.join();
}
ui.btn_Dispaly->setText("Stop");
thread_run_flag_ = true;
thread_Displayer_ = std::thread(&QtGuiApplication::thread_Displayer_fn,
this);
}
}
void QtGuiApplication::thread_Displayer_fn()
{
double y_max_ = 0;
double y_min_ = 0;
while (thread_run_flag_)
{
QVector<double> x(16384), y(16384);
for (int i = 0; i<16384; ++i)
{
x[i] = i;
y[i] = x[i];
if (y[i] > y_max_)
y_max_ = y[i];
if (y[i] < y_min_)
y_min_ = y[i];
}
plot_->yAxis->setRange(y_min_, y_max_);
plot_->graph(0)->setData(x, y);
plot_->replot();
}
}
但是當我啟動代碼時會發生此錯誤:
“無法將事件發送到其他線程擁有的對象”
我該如何解決?
您需要(或者至少這就是它的工作方式)創建一個信號,該信號將在線程中的for循環的每次迭代中發出。 然后,將此信號連接到將實際更新數據的插槽
class QtGuiApplication : public QWidget
{
Q_OBJECT
public:
explicit QtGuiApplication(QWidget *parent = 0);
~QtGuiApplication();
private slots:
void setPlotData(QVector<double> x,QVector<double> y);
void pushButtonClicked();
signals:
void newData(QVector<double> x, QVector<double> y);
private:
Ui::QtGuiApplication *ui;
QCustomPlot* plot_;
std::thread thread_Displayer_;
bool thread_run_flag_ = false;
void thread_Displayer_fn();
};
double fRand(double fMin, double fMax){
double f = (double)rand() / RAND_MAX;
return fMin + f * (fMax - fMin);
}
QtGuiApplication::QtGuiApplication(QWidget *parent) :
QWidget(parent),
ui(new Ui::QtGuiApplication)
{
// Set up UI
ui->setupUi(this);
plot_ = ui->qcustomplot;
// Register data type for signals
qRegisterMetaType<QVector<double>>("QVector<double>");
// Prepare graph
plot_->addGraph();
// Connect
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(pushButtonClicked()));
connect(this,SIGNAL(newData(QVector<double>,QVector<double>)),this,SLOT(setPlotData(QVector<double>,QVector<double>)));
}
QtGuiApplication::~QtGuiApplication()
{
delete ui;
}
void QtGuiApplication::pushButtonClicked()
{
if (thread_run_flag_)
{
ui->pushButton->setText("Display");
thread_run_flag_ = false;
if (thread_Displayer_.joinable())
{
thread_Displayer_.join();
}
}
else
{
thread_run_flag_ = false;
if (thread_Displayer_.joinable())
{
thread_Displayer_.join();
}
ui->pushButton->setText("Stop");
thread_run_flag_ = true;
thread_Displayer_ = std::thread(&QtGuiApplication::thread_Displayer_fn,
this);
}
}
void QtGuiApplication::setPlotData(QVector<double> x, QVector<double> y)
{
plot_->graph(0)->setData(x, y);
plot_->rescaleAxes();
plot_->replot();
}
void QtGuiApplication::thread_Displayer_fn()
{
while (thread_run_flag_)
{
QVector<double> x(ui->spinBox->value()), y(ui->spinBox->value());
for (int i = 0; i<ui->spinBox->value(); ++i)
{
x[i] = i;
y[i] = fRand(0,10);
}
emit newData(x,y);
usleep(ui->doubleSpinBox->value()*1000);// convert to us
}
}
請注意,我在發射后還添加了usleep
函數。 如果您不放置它,您將無法再次按下該按鈕並停止,我認為這是因為數據發送的速率很高。
在這里您可以找到整個示例。
使此函數靜態並嘗試void QtGuiApplication::thread_Displayer_fn()
static void QtGuiApplication::thread_Displayer_fn()
因為從類QtGuiApplication創建的對象已經由主線程擁有,並且您正在嘗試使用上述語句從另一個線程(子線程)中調用該對象的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.