Send data packets to multiple windows/widgets
-
wrote on 24 Feb 2023, 17:14 last edited by
I have one
QMainWindow
that opens DLL and receives data from it.
ThisQMainWindow
has different other windows opened, and holds its reference to it.I'd like to make a generic "driver" where each new window can subscribe to receive packets coming from DLL. Right now, when DLL packet arrives, it gets written to queue, which is later processed in
QTimer
callback, every 50ms at the moment.What is the correct and suggested way from Qt to achieve such task?
I see one option with signals:
QMainWindow
creates signal object that is emitted on every DLL message- New window, when created, receives pointer to parent, and can subscribe to signal. Signal will therefore have multiple connections
- Use
closeEvent
to disconnect from signal
Is this the right way?
-
I have one
QMainWindow
that opens DLL and receives data from it.
ThisQMainWindow
has different other windows opened, and holds its reference to it.I'd like to make a generic "driver" where each new window can subscribe to receive packets coming from DLL. Right now, when DLL packet arrives, it gets written to queue, which is later processed in
QTimer
callback, every 50ms at the moment.What is the correct and suggested way from Qt to achieve such task?
I see one option with signals:
QMainWindow
creates signal object that is emitted on every DLL message- New window, when created, receives pointer to parent, and can subscribe to signal. Signal will therefore have multiple connections
- Use
closeEvent
to disconnect from signal
Is this the right way?
wrote on 25 Feb 2023, 11:19 last edited by mpergand@tilz0R said in Send data packets to multiple windows/widgets:
I have one QMainWindow that opens DLL and receives data from it.
This QMainWindow has different other windows opened, and holds its reference to it.If mainWindow has a ref to child windows, why not send data directly to them ?
To manage child windows deleting, you can use QPointer as it will be set to null.
Here a standalone example:class ChildWindow : public QWidget { public: ChildWindow(QWidget* parent=nullptr) : QWidget(parent) { setAttribute(Qt::WA_DeleteOnClose); } void setData(const QByteArray& data) { qDebug()<<objectName()<<data; } }; class MainWin : public QMainWindow { public: MainWin() : QMainWindow() { // use a timer to simulate incoming data QTimer* timer=new QTimer(this); connect(timer, &QTimer::timeout,this,[this]() { static int i=0; i++; auto it = childWindows.begin(); while (it != childWindows.end()) { if (*it==nullptr) // removed from the vector if child win deleted/closed it = childWindows.erase(it); else { (**it).setData(QString("Data %1").arg(i).toLatin1()); ++it; } } }); timer->start(1000); for(int i=0; i<3; i++) { ChildWindow* w=new ChildWindow; w->setObjectName(QString("Child %1").arg(i+1)); w->setWindowTitle(w->objectName()); w->show(); childWindows<<w; } } private: QVector<QPointer<ChildWindow> > childWindows; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWin win; win.setWindowTitle("Main WIndow"); win.show(); return app.exec(); }
-
I have one
QMainWindow
that opens DLL and receives data from it.
ThisQMainWindow
has different other windows opened, and holds its reference to it.I'd like to make a generic "driver" where each new window can subscribe to receive packets coming from DLL. Right now, when DLL packet arrives, it gets written to queue, which is later processed in
QTimer
callback, every 50ms at the moment.What is the correct and suggested way from Qt to achieve such task?
I see one option with signals:
QMainWindow
creates signal object that is emitted on every DLL message- New window, when created, receives pointer to parent, and can subscribe to signal. Signal will therefore have multiple connections
- Use
closeEvent
to disconnect from signal
Is this the right way?
wrote on 24 Feb 2023, 18:35 last edited by@tilz0R
This is about how I would do it in Qt. Except I wouldn't pass a "pointer to parent [main window]" to other windows. Create an object to emit the signals rather than having it a part of the main window, other windows can place slots on it without accessing the main window. -
Hi,
As @JonB suggests, create a controller object that manages the interaction with that dll.
You can then have an instance of it in your main window and connect all the "sub-windows" to that controller.
From the looks of it, none of these widgets needs to know anything about the controller. Give them a proper slot to receive the data.
-
@tilz0R
This is about how I would do it in Qt. Except I wouldn't pass a "pointer to parent [main window]" to other windows. Create an object to emit the signals rather than having it a part of the main window, other windows can place slots on it without accessing the main window. -
There's no need for any singleton.
-
@JonB So your suggestion is to have a singleton object(that extends
QObject
) where each new instance who wants to receive packets, can get instance and connect to it?wrote on 24 Feb 2023, 20:23 last edited by JonB -
-
@JonB This will then allow to receive slots from spawn windows to the main one. Correct?
What about the opposite way? Is there a good example not to shoot myself to the knee?
wrote on 25 Feb 2023, 08:47 last edited by JonB@tilz0R
Yes, main window will gothis->otherWindow = new OtherWindow(this); connect(this->dllSignaller, &DllSignaller::packetArrived, this->otherWindow, &OtherWindow::onPacketArrivedSlot);
The "opposite way", assuming you mean the "other windows" would have to know about the main window in order to get at the DLL signaller object, is not a good design. It means they are dependent on your main window, while there is no need for them to be. The general rule is it's OK for parents to know about children but try to make children not know about parents.
-
@tilz0R
Yes, main window will gothis->otherWindow = new OtherWindow(this); connect(this->dllSignaller, &DllSignaller::packetArrived, this->otherWindow, &OtherWindow::onPacketArrivedSlot);
The "opposite way", assuming you mean the "other windows" would have to know about the main window in order to get at the DLL signaller object, is not a good design. It means they are dependent on your main window, while there is no need for them to be. The general rule is it's OK for parents to know about children but try to make children not know about parents.
-
@JonB OK - thanks makes sense in DLL direction. I suppose main window should then do the same to detect when child window is closed (but not destroyed in the memory). To disconnect sending packets there.
wrote on 25 Feb 2023, 09:53 last edited by@tilz0R
It could, if say you make the child emit a "closed" signal by overriding itscloseEvent()
. And then you'll have to attach its re-open event too.Or, why does the main window actually need to detach closed child from signal? Child could equally detect it is closed and not both to do work in its slot.
-
I have one
QMainWindow
that opens DLL and receives data from it.
ThisQMainWindow
has different other windows opened, and holds its reference to it.I'd like to make a generic "driver" where each new window can subscribe to receive packets coming from DLL. Right now, when DLL packet arrives, it gets written to queue, which is later processed in
QTimer
callback, every 50ms at the moment.What is the correct and suggested way from Qt to achieve such task?
I see one option with signals:
QMainWindow
creates signal object that is emitted on every DLL message- New window, when created, receives pointer to parent, and can subscribe to signal. Signal will therefore have multiple connections
- Use
closeEvent
to disconnect from signal
Is this the right way?
wrote on 25 Feb 2023, 11:19 last edited by mpergand@tilz0R said in Send data packets to multiple windows/widgets:
I have one QMainWindow that opens DLL and receives data from it.
This QMainWindow has different other windows opened, and holds its reference to it.If mainWindow has a ref to child windows, why not send data directly to them ?
To manage child windows deleting, you can use QPointer as it will be set to null.
Here a standalone example:class ChildWindow : public QWidget { public: ChildWindow(QWidget* parent=nullptr) : QWidget(parent) { setAttribute(Qt::WA_DeleteOnClose); } void setData(const QByteArray& data) { qDebug()<<objectName()<<data; } }; class MainWin : public QMainWindow { public: MainWin() : QMainWindow() { // use a timer to simulate incoming data QTimer* timer=new QTimer(this); connect(timer, &QTimer::timeout,this,[this]() { static int i=0; i++; auto it = childWindows.begin(); while (it != childWindows.end()) { if (*it==nullptr) // removed from the vector if child win deleted/closed it = childWindows.erase(it); else { (**it).setData(QString("Data %1").arg(i).toLatin1()); ++it; } } }); timer->start(1000); for(int i=0; i<3; i++) { ChildWindow* w=new ChildWindow; w->setObjectName(QString("Child %1").arg(i+1)); w->setWindowTitle(w->objectName()); w->show(); childWindows<<w; } } private: QVector<QPointer<ChildWindow> > childWindows; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWin win; win.setWindowTitle("Main WIndow"); win.show(); return app.exec(); }
-
@tilz0R said in Send data packets to multiple windows/widgets:
I have one QMainWindow that opens DLL and receives data from it.
This QMainWindow has different other windows opened, and holds its reference to it.If mainWindow has a ref to child windows, why not send data directly to them ?
To manage child windows deleting, you can use QPointer as it will be set to null.
Here a standalone example:class ChildWindow : public QWidget { public: ChildWindow(QWidget* parent=nullptr) : QWidget(parent) { setAttribute(Qt::WA_DeleteOnClose); } void setData(const QByteArray& data) { qDebug()<<objectName()<<data; } }; class MainWin : public QMainWindow { public: MainWin() : QMainWindow() { // use a timer to simulate incoming data QTimer* timer=new QTimer(this); connect(timer, &QTimer::timeout,this,[this]() { static int i=0; i++; auto it = childWindows.begin(); while (it != childWindows.end()) { if (*it==nullptr) // removed from the vector if child win deleted/closed it = childWindows.erase(it); else { (**it).setData(QString("Data %1").arg(i).toLatin1()); ++it; } } }); timer->start(1000); for(int i=0; i<3; i++) { ChildWindow* w=new ChildWindow; w->setObjectName(QString("Child %1").arg(i+1)); w->setWindowTitle(w->objectName()); w->show(); childWindows<<w; } } private: QVector<QPointer<ChildWindow> > childWindows; }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWin win; win.setWindowTitle("Main WIndow"); win.show(); return app.exec(); }
wrote on 28 Feb 2023, 21:04 last edited byThanks to all - I learnt something new, especially who shall call connect to signals.
-
1/12