Solved understaing part of an example from qcustomplot
-
Hi, so I am looking at using qcustomplot to do some real time graphing, and saw an example on their website that I thought I would follow, here is the link https://www.qcustomplot.com/index.php/demos/realtimedatademo
And after modifying the code to remove all the deprecated function with the new replacements. I am left with one errordataTimer was not declared in this scope
Now I understand the error I am just unsure from the example what dataTimer is or what its suppose to do/be, and there isnt any other information on the page apart from this code.
It also says on the page realTimeDataSlot() called by timer but I am also unsure as to what this is.So my question is does anyone know what either of these two things are/suppose to be.
code shown below
#include "widget.h" #include "ui_widget.h" #include <QTimer> #include <QTime> #include "qcustomplot.h" #include <QRandomGenerator> #include <qelapsedtimer.h> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); Widget::makePlot(); } Widget::~Widget() { delete ui; } void Widget::makePlot(){ ui->customPlot->addGraph(); // blue line ui->customPlot->graph(0)->setPen(QPen(QColor(40, 110, 255))); ui->customPlot->addGraph(); // red line ui->customPlot->graph(1)->setPen(QPen(QColor(255, 110, 40))); QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); timeTicker->setTimeFormat("%h:%m:%s"); ui->customPlot->xAxis->setTicker(timeTicker); ui->customPlot->axisRect()->setupFullAxesBox(); ui->customPlot->yAxis->setRange(-1.2, 1.2); // make left and bottom axes transfer their ranges to right and top axes: connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange))); connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange))); // setup a timer that repeatedly calls MainWindow::realtimeDataSlot: connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); dataTimer.start(0); // Interval 0 means to refresh as fast as possible }
Thanks in advance,
Dean -
for completeness for anyone else getting this error I had the realtimeDataSlot() declared under public in the .h file and it should have been in the private slots:
-
@Dean21
Hi. Well, that example does look a bit "incomplete".- You would need to add a
QTime dataTimer
. - You would need to put the code they give for
realtimeDataSlot
into a method (slot) namedvoid realtimeDataSlot()
. - The
dataTimer.start(0); // Interval 0 means to refresh as fast as possible
means that timer will tick/expire as fast as possible, repeatedly calling therealtimeDataSlot()
. I don't know whether this would make the application very "busy" and unresponsive!
TBH that example looks rather old. Use of old-style Qt signal & slot syntax which was updated in Qt to new style a decade ago,
static
variables etc. - You would need to add a
-
@Dean21 said in understaing part of an example from qcustomplot:
dataTimer was not declared in this scope
Simply download the source code: https://www.qcustomplot.com/release/2.1.1/QCustomPlot.tar.gz
Extract the archive and navigate to examples/plots and open mainwindow.h file... -
@JonB Hi thanks for your response by put the code they give for realtimeDataSlot into a method, do you mean I need to rename the void function I made to realtimeDataSlot?
And yes I gathered it was a bit old with the amount of deprecated functions they had used,
Thanks in advance,
Dean -
@Dean21
The code has// setup a timer that repeatedly calls MainWindow::realtimeDataSlot: connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot()));
You need a
MainWindow::realtimeDataSlot()
to make this work. But since you have made your class beWidget
instead ofMainWindow
per the comment, that would beWidget::realtimeDataSlot()
for you. That is not yourWidget::makePlot()
, it is for the code they give inrealtimeDataSlot, called by timer:
which I don't see you have entered.
If the
connect()
used the modern syntax:connect(&dataTimer, &QTimer::timeout, this, &Widget::realtimeDataSlot);
you would get (compile-time) errors until your code is correct. Using old style
SIGNAL
/SLOT()
macros is unhelpful. -
@JonB right I see I will adapt it to the newer syntax, once I get the default program to work, following what @jsulm said I have been modifying the code in the examples/plots directory, I have edited it down to just the example I want, but I cant copy and paste the code into a different project as I always get an error
‘class Ui::Widget’ has no member named ‘statusBar’
And when I look inside the example ui file they have a statusBar but I cant find a status bar in the widget list, I have tried including the statusbar library, but the example code doesnt have it so I am unsure how the example can work and not mine.
I also get this run time error, I understand this could be to do with what you said about the old syntax, but I dont understand how the example can work and not a (what i think) to be an exact copy in a different file
qt.core.qobject.connect: QObject::connect: No such slot Widget::realtimeDataSlot() in ../qcustomplot_new/widget.cpp:106 qt.core.qobject.connect: QObject::connect: (receiver name: 'Widget')
my code of the .h and .cpp files are shown below
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include "/home/dave/qcustomplot_new/qcustomplot.h" QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void setupDemo(int demoIndex); void setupRealtimeDataDemo(QCustomPlot *customPlot); void realtimeDataSlot(); private slots: //void makePlot(); private: Ui::Widget *ui; QTimer dataTimer; QString demoName; QCPItemTracer *itemDemoPhaseTracer; int currentDemoIndex; }; #endif // WIDGET_H
#include "widget.h" #include "ui_widget.h" #include <QDebug> #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) # include <QDesktopWidget> #endif #include <QScreen> #include <QMessageBox> #include <QMetaEnum> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); setGeometry(400, 250, 542, 390); setupRealtimeDataDemo(ui->customPlot); } void Widget::setupDemo(int demoIndex) { setupRealtimeDataDemo(ui->customPlot); setWindowTitle("QCustomPlot: "+demoName); //statusBar()->clearMessage(); //currentDemoIndex = demoIndex; ui->customPlot->replot(); } void Widget::setupRealtimeDataDemo(QCustomPlot *customPlot) { demoName = "Real Time Data Demo"; // include this section to fully disable antialiasing for higher performance: customPlot->setNotAntialiasedElements(QCP::aeAll); QFont font; font.setStyleStrategy(QFont::NoAntialias); customPlot->xAxis->setTickLabelFont(font); customPlot->yAxis->setTickLabelFont(font); customPlot->legend->setFont(font); customPlot->addGraph(); // blue line customPlot->graph(0)->setPen(QPen(QColor(40, 110, 255))); customPlot->addGraph(); // red line customPlot->graph(1)->setPen(QPen(QColor(255, 110, 40))); QSharedPointer<QCPAxisTickerTime> timeTicker(new QCPAxisTickerTime); timeTicker->setTimeFormat("%h:%m:%s"); customPlot->xAxis->setTicker(timeTicker); customPlot->axisRect()->setupFullAxesBox(); customPlot->yAxis->setRange(-1.2, 1.2); // make left and bottom axes transfer their ranges to right and top axes: connect(customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->xAxis2, SLOT(setRange(QCPRange))); connect(customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), customPlot->yAxis2, SLOT(setRange(QCPRange))); // setup a timer that repeatedly calls Widget::realtimeDataSlot: connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot())); dataTimer.start(0); // Interval 0 means to refresh as fast as possible } void Widget::realtimeDataSlot() { static QTime timeStart = QTime::currentTime(); // calculate two new data points: double key = timeStart.msecsTo(QTime::currentTime())/1000.0; // time elapsed since start of demo, in seconds static double lastPointKey = 0; if (key-lastPointKey > 0.002) // at most add point every 2 ms { // add data to lines: ui->customPlot->graph(0)->addData(key, qSin(key)+std::rand()/(double)RAND_MAX*1*qSin(key/0.3843)); ui->customPlot->graph(1)->addData(key, qCos(key)+std::rand()/(double)RAND_MAX*0.5*qSin(key/0.4364)); // rescale value (vertical) axis to fit the current data: //ui->customPlot->graph(0)->rescaleValueAxis(); //ui->customPlot->graph(1)->rescaleValueAxis(true); lastPointKey = key; } // make key axis range scroll with the data (at a constant range size of 8): ui->customPlot->xAxis->setRange(key, 8, Qt::AlignRight); ui->customPlot->replot(); // calculate frames per second: // static double lastFpsKey; // static int frameCount; // ++frameCount; // if (key-lastFpsKey > 2) // average fps over 2 seconds // { // ui->statusBar->showMessage( // QString("%1 FPS, Total Data points: %2") // .arg(frameCount/(key-lastFpsKey), 0, 'f', 0) // .arg(ui->customPlot->graph(0)->data()->size()+ui->customPlot->graph(1)->data()->size()) // , 0); // lastFpsKey = key; // frameCount = 0; // } } //commented out because of the staus bar error, thats why I included it Widget::~Widget() { delete ui; }
-
@Dean21 said in understaing part of an example from qcustomplot:
‘class Ui::Widget’ has no member named ‘statusBar’
You took an example for a
QMainWindow
, which has a statusbar, and chose to change it to aQWidget
, which does not. You have to make necessary changes if you change things.qt.core.qobject.connect: QObject::connect: No such slot Widget::realtimeDataSlot() in ../qcustomplot_new/widget.cpp:106
It tells you what the error is. Please think about the changes you make.
-
@JonB oh I see, so is it not possible to have this work in a widget application, (I have never used main window) so dont know much about it
-
@Dean21
If you don't use aQMainWindow
where do you expect the status bar to be?
Yes you can create status bars in widgets if you wish. AQMainWindow
is an example of aQWidget
which has had a status bar added.
You need to peruse documentation if you want to understand/alter things. -
@JonB I see I was under the impression that the only difference between main window and widget was the names used in the code. Clearly I see this is not the case, I thought it would be easiest to just convert my widget project to a mainwindow project by adjusting my .cpp file and .h file. However I get 2 errors saying
mem-initializer for ‘MainWindow::ui’ follows constructor delegation constructor delegates to itself
it says the error is on line ui(new Ui::MainWindow) but i checked by making a new main widget project and it is identical to what is auto generate when you make a new project. I emitted the rest of the code from the project
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : MainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); }
.h file
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "QMMqttClient.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); QMMqttClient client; private slots: void on_pushButton_clicked(); void int_or_string_LV(); void int_or_string_HV(); void Display_Int_Error(int); void Empty_string_Error(int); void Display_Range_Error(int); void Display_Default(int); void Display_success_msg(int); void Vbias_min_max_check(QString, int); void msg_functionality(); void Light_level_before_amplification(QString); void on_lineEdit_returnPressed(); void on_HV_pushButton_pressed(); void on_HV_lineEdit_returnPressed(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
-
@Dean21 said in understaing part of an example from qcustomplot:
be easiest to just convert my widget project to a mainwindow project by adjusting my .cpp file and .h file.
No, because you are (presumably?) using a
.ui
Designer file where you designed it with aQWidget
instead of aQMainWindow
? Or other such. At any rate you have a mistake.You might try a forced clean/rebuild of everything.
I'm sorry, but if you don't know what you doing you cannot just hack away changing things and hope it works. If you were given working code for a
QMainWindow
then I suggest you stick with that (restart with what they gave you?) rather then change to aQWidget
because you feel like it. Get that working first, then consider changing. Or, maybe, stick with yourQWidget
and get rid of the statusbar stuff. Otherwise it's like sticking fingers in a dyke. -
for completeness for anyone else getting this error I had the realtimeDataSlot() declared under public in the .h file and it should have been in the private slots: