QT Signals And Slots Between 2 Classes
-
From what I've understood, I should be very close in my code. I've got two separate Q_OBJECT objects housed under my main program class, but when it comes time to connect the Signal to the Slot I run into an issue.
The UIGraph object has a button, Recalculate, which when clicked will emit the signal CreateNewRun. I want this to trigger a function in the PID object which will execute some code.
Optimally, I'll have the PID object then emit a signal afterwards to tell the UI to update based on the code available or pass a reference through the signal of the new code to be plotted. I feel like I'm missing something simple here. Any thoughts?
Code below:
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // UI Component graph = new UIGraph(this); QWidget* graphObject = graph->SetupUI(); // PID Component pid = new PIDFunction(); // Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun); setCentralWidget(graphObject); }mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "UI/uigraph.h" #include "PID/pidfunction.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; UIGraph *graph; PIDFunction *pid; }; #endif // MAINWINDOW_HUIGraph.h
#ifndef UIGRAPH_H #define UIGRAPH_H #include <QWidget> #include <QMainWindow> #include <QGroupBox> #include <QLabel> #include <QLineEdit> #include <QPushButton> #include <QVBoxLayout> #include <QComboBox> #include "qcustomplot.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE enum TextIndications{ ProprtionalGain, IntegralGain, DerivativeGain, LoopInterval, TargetValue, Period, Recalculate }; class UIGraph : public QWidget { Q_OBJECT public: UIGraph(QWidget *parent = nullptr); void GenerateNewData(); QWidget* SetupUI(); signals: void CreateNewRun(); private: Ui::MainWindow *ui; void PlotSetup(); void SetupControlColumn(); void PressRecalculateButton(); QGroupBox *gridGroupBox; QLabel *labels[6]; QLineEdit *lineEdits[6]; QPushButton *recalculate; QVBoxLayout *mainLayout; QGridLayout *layout; QCustomPlot *customPlot; QComboBox *signalStyle; QWidget *body; //private slots: // void GenerateNewGraph(); signals: }; #endif // UIGRAPH_Hpidfunction.h
#ifndef PIDFUNCTION_H #define PIDFUNCTION_H #include "functiongenerator.h" #include <QObject> enum FunctionType {_line, _sin, _saw, _triangle, _square, _curvTriCave, _curTriVex }; class PIDFunction : public FunctionGenerator, public QObject { Q_OBJECT public: PIDFunction(); void GenerateNextPoint(); QVector<double> yOutput; void Process(double val); double Calculate(double setpoint, double pv); void SetP(double p); void SetI(double i); void SetD(double d); void SetLoopInterval(int _dt); void SetTargetValue(double t); //void SetPeriod(int p); void SetWaveform(int); void Reset(); public slots: void GenerateNewRun(); private: // proportional, integral, derivative double kp, ki, kd; // loop interval time double dt; // Min/Max of manipulated variable double max, min; // integral double integral; // Previous Error double pre_error = 0; // Stored Error double storedError = 0; // Target Value double target = 0; // Period int period = 10; double previousError; FunctionType ft; }; #endif // PIDFUNCTION_H -
Conect the signal and slot where you have access to both classes.
-
From what I've understood, I should be very close in my code. I've got two separate Q_OBJECT objects housed under my main program class, but when it comes time to connect the Signal to the Slot I run into an issue.
The UIGraph object has a button, Recalculate, which when clicked will emit the signal CreateNewRun. I want this to trigger a function in the PID object which will execute some code.
Optimally, I'll have the PID object then emit a signal afterwards to tell the UI to update based on the code available or pass a reference through the signal of the new code to be plotted. I feel like I'm missing something simple here. Any thoughts?
Code below:
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // UI Component graph = new UIGraph(this); QWidget* graphObject = graph->SetupUI(); // PID Component pid = new PIDFunction(); // Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun); setCentralWidget(graphObject); }mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "UI/uigraph.h" #include "PID/pidfunction.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; UIGraph *graph; PIDFunction *pid; }; #endif // MAINWINDOW_HUIGraph.h
#ifndef UIGRAPH_H #define UIGRAPH_H #include <QWidget> #include <QMainWindow> #include <QGroupBox> #include <QLabel> #include <QLineEdit> #include <QPushButton> #include <QVBoxLayout> #include <QComboBox> #include "qcustomplot.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE enum TextIndications{ ProprtionalGain, IntegralGain, DerivativeGain, LoopInterval, TargetValue, Period, Recalculate }; class UIGraph : public QWidget { Q_OBJECT public: UIGraph(QWidget *parent = nullptr); void GenerateNewData(); QWidget* SetupUI(); signals: void CreateNewRun(); private: Ui::MainWindow *ui; void PlotSetup(); void SetupControlColumn(); void PressRecalculateButton(); QGroupBox *gridGroupBox; QLabel *labels[6]; QLineEdit *lineEdits[6]; QPushButton *recalculate; QVBoxLayout *mainLayout; QGridLayout *layout; QCustomPlot *customPlot; QComboBox *signalStyle; QWidget *body; //private slots: // void GenerateNewGraph(); signals: }; #endif // UIGRAPH_Hpidfunction.h
#ifndef PIDFUNCTION_H #define PIDFUNCTION_H #include "functiongenerator.h" #include <QObject> enum FunctionType {_line, _sin, _saw, _triangle, _square, _curvTriCave, _curTriVex }; class PIDFunction : public FunctionGenerator, public QObject { Q_OBJECT public: PIDFunction(); void GenerateNextPoint(); QVector<double> yOutput; void Process(double val); double Calculate(double setpoint, double pv); void SetP(double p); void SetI(double i); void SetD(double d); void SetLoopInterval(int _dt); void SetTargetValue(double t); //void SetPeriod(int p); void SetWaveform(int); void Reset(); public slots: void GenerateNewRun(); private: // proportional, integral, derivative double kp, ki, kd; // loop interval time double dt; // Min/Max of manipulated variable double max, min; // integral double integral; // Previous Error double pre_error = 0; // Stored Error double storedError = 0; // Target Value double target = 0; // Period int period = 10; double previousError; FunctionType ft; }; #endif // PIDFUNCTION_H@JPatrick said in QT Signals And Slots Between 2 Classes:
// Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun);Hi and welcome.
If you showed/looked at the error message you would get further.
Get rid of the
SIGNAL/SLOT()macros approach and stick to the second case new style for all your work. There the error message should be telling you (read it carefully!) what is wrong with your parameter types. (Hint:&graphand&pidare wrong, you're almost there but over-complicating....) -
Was this connect really there when I read it the first time? Strange...
Take a look at https://doc.qt.io/qt-5/signalsandslots.html -
From what I've understood, I should be very close in my code. I've got two separate Q_OBJECT objects housed under my main program class, but when it comes time to connect the Signal to the Slot I run into an issue.
The UIGraph object has a button, Recalculate, which when clicked will emit the signal CreateNewRun. I want this to trigger a function in the PID object which will execute some code.
Optimally, I'll have the PID object then emit a signal afterwards to tell the UI to update based on the code available or pass a reference through the signal of the new code to be plotted. I feel like I'm missing something simple here. Any thoughts?
Code below:
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // UI Component graph = new UIGraph(this); QWidget* graphObject = graph->SetupUI(); // PID Component pid = new PIDFunction(); // Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun); setCentralWidget(graphObject); }mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "UI/uigraph.h" #include "PID/pidfunction.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; UIGraph *graph; PIDFunction *pid; }; #endif // MAINWINDOW_HUIGraph.h
#ifndef UIGRAPH_H #define UIGRAPH_H #include <QWidget> #include <QMainWindow> #include <QGroupBox> #include <QLabel> #include <QLineEdit> #include <QPushButton> #include <QVBoxLayout> #include <QComboBox> #include "qcustomplot.h" QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE enum TextIndications{ ProprtionalGain, IntegralGain, DerivativeGain, LoopInterval, TargetValue, Period, Recalculate }; class UIGraph : public QWidget { Q_OBJECT public: UIGraph(QWidget *parent = nullptr); void GenerateNewData(); QWidget* SetupUI(); signals: void CreateNewRun(); private: Ui::MainWindow *ui; void PlotSetup(); void SetupControlColumn(); void PressRecalculateButton(); QGroupBox *gridGroupBox; QLabel *labels[6]; QLineEdit *lineEdits[6]; QPushButton *recalculate; QVBoxLayout *mainLayout; QGridLayout *layout; QCustomPlot *customPlot; QComboBox *signalStyle; QWidget *body; //private slots: // void GenerateNewGraph(); signals: }; #endif // UIGRAPH_Hpidfunction.h
#ifndef PIDFUNCTION_H #define PIDFUNCTION_H #include "functiongenerator.h" #include <QObject> enum FunctionType {_line, _sin, _saw, _triangle, _square, _curvTriCave, _curTriVex }; class PIDFunction : public FunctionGenerator, public QObject { Q_OBJECT public: PIDFunction(); void GenerateNextPoint(); QVector<double> yOutput; void Process(double val); double Calculate(double setpoint, double pv); void SetP(double p); void SetI(double i); void SetD(double d); void SetLoopInterval(int _dt); void SetTargetValue(double t); //void SetPeriod(int p); void SetWaveform(int); void Reset(); public slots: void GenerateNewRun(); private: // proportional, integral, derivative double kp, ki, kd; // loop interval time double dt; // Min/Max of manipulated variable double max, min; // integral double integral; // Previous Error double pre_error = 0; // Stored Error double storedError = 0; // Target Value double target = 0; // Period int period = 10; double previousError; FunctionType ft; }; #endif // PIDFUNCTION_H@JPatrick said in QT Signals And Slots Between 2 Classes:
// UI Component graph = new UIGraph(this); QWidget* graphObject = graph->SetupUI(); // PID Component pid = new PIDFunction(); // Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun);No this cannot work,
connect()sender and receiver should be pointers not pointer of pointer!// Old syntax connect(graph, SIGNAL(CreateNewRun()), pid, SLOT(GenerateNewRun())); // new syntax connect(graph, &UIGraph::CreateNewRun, pid, &PIDFunction::GenerateNewRun); -
@JPatrick said in QT Signals And Slots Between 2 Classes:
// Neither of these successfully resolve connect(&graph, SIGNAL(CreateNewRun()), this->pid, SLOT(GenerateNewRun())); connect(&graph, &UIGraph::CreateNewRun, &pid, &PIDFunction::GenerateNewRun);Hi and welcome.
If you showed/looked at the error message you would get further.
Get rid of the
SIGNAL/SLOT()macros approach and stick to the second case new style for all your work. There the error message should be telling you (read it carefully!) what is wrong with your parameter types. (Hint:&graphand&pidare wrong, you're almost there but over-complicating....) -
@JonB and @KroMignon
Good grief I feel like a fool.
connect(graph, &UIGraph::CreateNewRun, pid, &PIDFunction::GenerateNewRun);worked without issue, and now I'm running again. Thank you for pointing out the obvious to me.
@JPatrick
You were close, for a noob you did well on your own, you should see some of the questions we get! :) Like I said, do yourself a favour and stick to that new styleconnect()syntax, then you get compile-time incompatibility error messages, look at those closely and you should be able to discern the cause.