Solved Connecting 2 different classes together
-
@JonB Ah I think I got it now. Let's say I have 2 different classes that linked each other with including header file and forward declaration. What I should have done is: Using connects in one of that classes' cpp file. What I tried to do is using connects in the both of the cpp files which was incorrect I guess. Using connects in only one of these might work I guess. But does it matter in which class I use connects? The one included other's header file in it, or the one that has a forward declaration in it?
-
@JonB I am starting to learn them right now. Thanks!
-
@GunkutA
You certainly do not want two connects for one signal-slot connection.You should never connect a signal in class A to a slot in class B from within class A. In principle, signallers never know about slotters, but slotters can know about signallers. You may do the connect from the class B slot class, or you may do it from elsewhere which knows about both A & B.
It might be that after this you no longer need that "circular dependency", maybe you had that to try to do the incorrect double-
connect()
? It may well be that the slot class need to include the details of the signal class, to achieve theconnect()
, but from what you describe why does the signal class need to know anything at all about the slot class?However, for your current issue. Comment out the
connect()
s completely, temporarily! Do thenew USB
. Does that crash? -
Also I forgot to mention that, there is also a connect and declaration in the usb.cpp file like this:
protocolFormInstance = new protocolForm(); connect(this,SIGNAL(sendCOMPort(QString)),protocolFormInstance , SLOT(receiveCOMPort(QString)));
And the header file of protocolForm there is this line:
USB* USBInstance;
Now when I commented out these all lines from USB header and cpp file. The connect and declaration line the protocolform.cpp file do not crash anymore. So I believe I should transfer the connect line I commented out from the USB.cpp file to protocolform.cpp.
So at the end protocol.cpp file should include both of the connects. However, when I tried that I cannot use the sendComPort() signal which is declared in the USB header. Maybe I should make USB class a child class of the protocolform class. -
@GunkutA
First, not surprisingly, I now see you have changed what yourconnect()
looks like for the slot side. Using theSLOT()
macro hides incorrect parameter passing. Your new-style connect really should look like:connect(this, &ThisClassName::sendCOMPort, protocolFormInstance , &ProtocolFormClassName::receiveCOMPort);
But looking at this, it seems likely it's the wrong way round. If
this
isUSB
, and that is the signaller, then the above should be done within theProtocolForm
slot class:connect(USBinstance, &USB::sendCOMPort, this, &ProtocolFormClassName::receiveCOMPort);
Maybe I should make USB class a child class of the protocolform class.
Absolutely not!
So at the end protocol.cpp file should include both of the connects.
What both
connect()
s? You have shown oneconnect()
. What is the secondconnect()
? I want to see both theconnect()
s you have. -
@JonB Okay I tried all possibilities and found what causes the crash ( I hope). So when I declare USB in protocolform and protocol form in USB.cpp , at the same time program gets crashed :
USB.h
private: protocolForm* protocolFormInstance;
USB.ccp
protocolFormInstance = new protocolForm;
Protocolform.h
private: Ui::protocolForm *ui; USB* USBInstance;
Protocolform.cpp
USBInstance = new USB;
Eventough all the connect lines are commented out, that declarations cause crash I believe. ( Btw I can send all the headers and cpp files in here if it wouldn't be too long.)
-
It matters where these instantiation lines are. If you have both
new
s in constructors then it will surely crash (infinite loop!). If you separate them so that one object is create later, it will work. -
@GunkutA
Protocolform
is some kind of UI widget/form, right? While, at a guess,USB
is not a GUI element?Then I get why
Protocolform
needs to know aboutUSB
, to connect a slot to its signal(s). That sounds OK.But, if that is so, why does
USB
class need to know anything aboutProtocolform
UI class?? Why doesUSB.h/cpp
need those references toprotocolForm
? It sounds like it should not, and then you would get of your circular dependency.... -
Because I was planning to know button presses from GUI ( which is protocolForm) in the USB class. Then I would connect to the USB port.
-
@sierdzio I believe they are in constructors :(
Complete USB.cpp code ( as an example) looks like this:#include "usb.h" #include <QtSerialPort> #include <QSerialPortInfo> #include <QtSerialPort/QSerialPortInfo> #include <QtSerialPort/QSerialPortInfo> #include <QSerialPort> #include "mainwindow.h" #include "protocolform.h" #include <QDebug> USB::USB(QObject *parent) : QObject(parent) { QSerialPort *serial; timer = new QTimer(this); serial = new QSerialPort(this); connect(timer, SIGNAL(timeout()), this, SLOT(timerTimeoutSLOT())); timer->start(1000); protocolFormInstance = new protocolForm; // protocolFormInstance = new protocolForm(); connect(this,&USB::sendCOMPort(QString),protocolFormInstance , &protocolForm::receiveCOMPort(QString)); } void USB::timerTimeoutSLOT() { qDebug()<<"Timed out..."; emit sendCOMPort("begin"); // Q_FOREACH(QSerialPortInfo port, QSerialPortInfo::availablePorts()) { // emit sendCOMPort(port.portName()); // } } void USB::receiveChosenComPort(const QString &ChosenComPort) { }
and the header of the USB:
#ifndef USB_H #define USB_H #include "protocolform.h" #include <QObject> class USB : public QObject { Q_OBJECT public: explicit USB(QObject *parent = nullptr); QTimer *timer; public slots: void timerTimeoutSLOT(); void receiveChosenComPort(const QString &ChosenComPort); signals: void sendCOMPort(const QString &COMPort); private: //protocolForm* protocolFormInstance; }; #endif // USB_H
-
@GunkutA said in Connecting 2 different classes together:
Because I was planning to know button presses from GUI ( which is protocolForm) in the USB class. Then I would connect to the USB port.
That is exactly what signals and slots are for. Your
USB
class does not need to know anything about any UI. It will simply have some slot, like for exampleonButtonPressed()
orsomethingHappened()
and it will respond to such event (signal). It does not need to know any more details. And if it does, then you can send the necessary information as argument in your signal and slot.Then, if
USB
needs to inform the UI about something, it emits a signal as well. -
protocolFormInstance = new protocolForm; // protocolFormInstance = new protocolForm(); connect(this,&USB::sendCOMPort(QString),protocolFormInstance , &protocolForm::receiveCOMPort(QString));
This is all in the wrong place/wrong way round. The
USB
class handles serial/USB activity. It should know nothing aboutprotocolForm
, it should notnew
it. As I wrote above, theconnect()
belongs in theprotocolForm
class.You need to stop typing/commenting out stuff and take time to understand the necessary approach correctly. I leave this to you/ @sierdzio now, as I have tried to explain and give examples of all I can....
-
@sierdzio Well the thing is, it needs to know the selected COM Port from the GUI. So there will be 3 COM Ports for example and when the button pressed, USB class will know the which COM Port is selected and then it will connect to it. So I believe I need to send COM Port info from GUI to USB class.
-
@GunkutA said in Connecting 2 different classes together:
@sierdzio Well the thing is, it needs to know the selected COM Port from the GUI. So there will be 3 COM Ports for example and when the button pressed, USB class will know the which COM Port is selected and then it will connect to it. So I believe I need to send COM Port info from GUI to USB class.
Yes, do it by argument. USB class does not need to know anything more. So, a minimal example:
// UI UiClass : public QWidget { Q_OBJECT USB *usb = nullptr; signals: void openPort(const int port) const; public: UiClass(QWidget *parent = nullptr) : public QWidget(parent) { usb = new USB; connect(this, &UiClass::openPort, usb, &USB::onOpenPort); } }; // USB class class USB : public QObject { Q_OBJECT public slots: void onOpenPort(const int port) { // Do something with the port } };
-
@sierdzio I got it, thank you for all the effort.