I need your advice on a program I'm coding right now. Let me first present you what it is.
Design
I'm designing a man-machine interface (MMI). In this MMI, there are two core elements:
The MainWindow:
This MainWindow is the base of everything. Important: Here, I launch in a thread a server that receives the data from a client. This data is very important to the next element.
Supervision
This window contains a QTableWidget, the goal is to show in pseudo-real time the data received on the server in the thread of MainWindow.
The Problem
The server in the thread owned by the MainWindow receive a structure every 10 mS. How can I send these data to the Supervision window if it's open? I was thinking of using shared memory, but not really sure about this, and doesn't really which method I have to use.
Some Solutions
I tried to implement the solution of Sebastian Lange :
An emit in the thread Server
A connect in the MainWindow
A slot in supervision
So now my thread Server emit a signal at every frame received. But how can I do the connect in the MainWindow and how will Supervision receive the struct emit in the signal?
Here's the code of my emit:
MainWindow* MainWindow::m_psMainWindow = nullptr; // C++ 11 nullptr
void MainWindow::emit_signal_TrameRecu(StructureSupervision::T_StructureSupervision* ptr){
emit signal_TrameRecu(ptr);
}
void MainWindow::lancerServeur(std::atomic<bool>& boolServer){
serveur s;
StructureSupervision::T_StructureSupervision* bufferStructureRecu;
while(boolServer){
bufferStructureRecu = s.receiveDataUDP();
if(bufferStructureRecu->SystemData._statutGroundFlight != 0){
m_psMainWindow->emit_signal_TrameRecu( bufferStructureRecu );
}
}
}
Queued Connections
Qt makes cross thread communication easy when you use queued connections.
Your calls to connect should use the Qt::QueuedConnection or Qt::BlockingQueuedConnection connection types.
Custom Types in Slots and Signals
To use custom types (structs) in slots, signals, QVariant and properties you need to declare and register the type to make it available to the Qt dynamic type system.
In your header (.hpp) use Q_DECLARE_METATYPE and in your source (.cpp) use qRegisterMetaType.
Worked Example
server.hpp
#ifndef SERVER_HPP
#define SERVER_HPP
#include <QtCore>
struct customdata
{
int id;
QDateTime tstamp;
};
Q_DECLARE_METATYPE(customdata)
class Server : public QThread
{
Q_OBJECT
public:
Server();
signals:
void sendData(const customdata& d);
protected:
virtual void run();
};
#endif
server.cpp
#include "server.hpp"
static const int customdata_metatype_id =
qRegisterMetaType<customdata>();
Server::Server() : QThread() {}
void Server::run()
{
customdata d;
d.id = 0;
for (int i = 0; i < 10; ++i)
{
d.id++;
d.tstamp = QDateTime::currentDateTime();
emit sendData(d);
sleep(1);
}
}
window.hpp
#ifndef WINDOW_HPP
#define WINDOW_HPP
#include <QtGui>
#include "server.hpp"
class Window : public QWidget
{
Q_OBJECT
public:
Window();
public slots:
void receiveData(const customdata& d);
private:
QListWidget* mList;
};
#endif
window.cpp
#include "window.hpp"
Window::Window() : QWidget(),mList(new QListWidget())
{
resize(400, 300);
QVBoxLayout* mainLayout = new QVBoxLayout();
mainLayout->addWidget(mList);
setLayout(mainLayout);
}
void Window::receiveData(const customdata& d)
{
QString str(QString("%1 %2").arg(d.id).arg(d.tstamp.toString()));
mList->addItem(str);
}
main.cpp
#include <QtGui>
#include "server.hpp"
#include "window.hpp"
int main(int argc, char** argv)
{
QApplication app(argc, argv);
Window win;
Server ser;
QObject::connect(
&ser, SIGNAL(sendData(customdata)),
&win, SLOT(receiveData(customdata)),
Qt::QueuedConnection);
win.show();
ser.start();
return app.exec();
}
test.pro
TEMPLATE=app
QT=core gui
HEADERS=server.hpp window.hpp
SOURCES=main.cpp server.cpp window.cpp
I once (in the days of Qt 3.2) implemented this cross thread communication using QApplication::postEvent (now QCoreApplication::postEvent). However nowadays best practise is to use promises and futures to communicate asynchronously between threads. Promises and futures has become a part of recent C++ standard and the concepts are also implemented separately as part of Qt 5 Concurrent framework. See http://qt-project.org/doc/qt-5/qtconcurrent-index.html
Related
I'm working on a C++ Qt GUI to remote control a ROS robot. I've read that the ros::spin() command should be issued in a seperate Thread so I basically have the usual MainWindow derived from QMainWindow whose constructor sets up the GUI elements, makes the Subscriber Objects subscribe to their respective topic (e.g. image_transport::Subscriber for sensor_msgs/Image topics) and also starts another Thread. For that I have derived a "RosThread" class from QThread that doesn't do anything but starting a ros:MultiThreadedSpinner when RosThread::run() is called.
As you can probably tell, I'm not exactly experienced when it comes to programming in general so my question is, wether the basic concept behind my project makes any sense to you?
Especially should I leave the NodeHandle and the Subscriber Objects in the MainWindow and setup the Subscriptions from the MainWindow Constructor?
Relevant code snippets:
mainwindow.cpp:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), itLeft(nh), itArm(nh)
{
//subscribe to cameras
imageSubLeft = itLeft.subscribe("/camera_1/image_raw", 1000, &MainWindow::camCallbackLeft, this);
imageSubArm = itArm.subscribe("/camera_2/image_raw", 1000, &MainWindow::camCallbackArm, this);
pagestack = new QStackedWidget;
page1 = new QWidget;
grid = new QGridLayout;
page1->setLayout(grid);
pagestack->addWidget(page1);
labelLeft = new QLabel;
labelMid = new QLabel;
grid->addWidget(labelLeft, 0, 0);
grid->addWidget(labelMid, 0, 1);
this->startSpinThread(); //starts the seperate Thread where run() is executed
this->setCentralWidget(pagestack);
this->setWindowState(Qt::WindowMaximized);
this->setMinimumSize(1024, 768);
}
MainWindow::~MainWindow(){}
void MainWindow::camCallbackLeft(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::camCallbackArm(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::closeEvent(QCloseEvent *event){/*some code*/}
void MainWindow::startSpinThread()
{
if(rosSpin.isRunning())
{
return;
}
//rosSpin is an Object of the of QThread derived class
rosSpin.start();
}
rosthread.h:
#ifndef ROSTHREAD_H
#define ROSTHREAD_H
#include <ros/ros.h>
#include <QThread>
class RosThread : public QThread
{
Q_OBJECT
public:
RosThread();
protected:
void run();
private:
ros::MultiThreadedSpinner spinner;
};
#endif // ROSTHREAD_H
rosthread.cpp:
#include "rosthread.h"
RosThread::RosThread()
{
}
void RosThread::run() {
spinner.spin();
}
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <ros/ros.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "gui_node");
QApplication app (argc, argv);
MainWindow *win = new MainWindow();
win->show();
return app.exec();
}
Actually, QThread is not intended to be used this way. Take a look at this blog article and this example.
But anyway, I would suggest the standard C++ threads.
Add std::unique_ptr<std::thread> thread; to your MainWindow class instead of the RosThread object.
To start a thread, use thread.reset(new std::thread([](){ static ros::MultiThreadedSpinner spinner; spinner.spin(); });. The smart pointer std::unique_ptr will automatically delete the thread object although you shouldn't forget to use std::thread::join() or std::thread::detach() before the resetting/destroying your std::unique_ptr object.
Another solution would be to put the ros::MultiThreadedSpinner object into your MainWindow class and create a std::thread using thread.reset(new std::thread(&ros::MultiThreadedSpinner::spin, spinner));.
In my opinion, you should put you NodeHandle and Subscriber objects into another class and use an object of this class as a member of MainWindow if they don't belong directly to MainWindow.
I created a minimal QT GUI example to update widgets from a worker thread based on the recommended approach in the The QThread 5.12 documentation.
As described in the QThread 5.12 documentation, the Worker class (with a potentially long void doWork(const QString ¶meter) method is:
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(const QString ¶meter) {
QString result;
/* ... here is the expensive or blocking operation ... */
emit resultReady(result);
}
signals:
void resultReady(const QString &result);
};
and the corresponding Controller class is:
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller() {
Worker *worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &);
signals:
void operate(const QString &);
};
Unlike sub-classing from a QThread, the approach shown in the documentation shows the recommended way that uses a controller and a worker that extends QObject rather than extending QThread and overriding the QThread::run method, however it does not show how these should be used in the context of a real example.
I need to use an QT Worker thread that updates widgets on a GUI using a timer.
I also need to be able to halt and restart/relaunch this thread with different parameters and I am having some trouble with how to do this correctly. indicates the preferred way to do this via a Controller and a Worker but the connect logic is a bit confusing.
The place where I need help is how to properly integrate the timer in my worker thread and also how to stop and restart a replacement worker when the current one has either finished or been interrupted and restarted.
My working code is made up of the following files.
Controller.h
#pragma once
// SYSTEM INCLUDES
#include <QObject>
#include <QThread>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Controller : public QObject
{
Q_OBJECT
QThread workerThread;
public:
Controller(/*MainWindow* mainWindow*/) {
auto worker = new Worker;
worker->moveToThread(&workerThread);
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
connect(this, &Controller::operate, worker, &Worker::doWork);
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
workerThread.start();
}
~Controller() {
workerThread.quit();
workerThread.wait();
}
public slots:
void handleResults(const QString &) {
// how do I update the mainWindow from here
}
signals:
void operate(int);
};
Worker.h
#pragma once
// SYSTEM INCLUDES
#include <QTimer>
#include <QObject>
#include <QEventLoop>
// APPLICATION INCLUDES
#include "Worker.h"
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
class Worker : public QObject
{
Q_OBJECT
public slots:
void doWork(int count) {
QString result = "finished";
// Event loop allocated in workerThread
// (non-main) thread affinity (as moveToThread)
// this is important as otherwise it would occur
// on the main thread.
QEventLoop loop;
for (auto i=0; i< count; i++) {
// wait 1000 ms doing nothing...
QTimer::singleShot(1000, &loop, SLOT(quit()));
// process any signals emitted above
loop.exec();
emit progressUpdate(i);
}
emit resultReady(result);
}
signals:
void progressUpdate(int secondsLeft);
void resultReady(const QString &result);
};
MainWindow.h - I needed to add a Controller member here. I also added an updateValue slot here where I wish to update the GUI. Unfortunately I don't know how to get the controller or the worker to connect a signal from the thread to update this slot.
#pragma once
// SYSTEM INCLUDES
#include <memory>
#include <QMainWindow>
// APPLICATION INCLUDES
// DEFINES
// EXTERNAL FUNCTIONS
// EXTERNAL VARIABLES
// CONSTANTS
// STRUCTS
// TYPEDEFS
// FORWARD DECLARATIONS
namespace Ui {
class MainWindow;
}
class Controller;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
void updateValue(int secsLeft);
private:
Ui::MainWindow *ui;
std::unique_ptr<Controller> mpController;
};
MainWindow.cpp -
#include <QThread>
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include "Controller.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, mpController(std::make_unique<Controller>())
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
emit mpController->operate(100);
}
void MainWindow::updateValue(int secsLeft)
{
ui->secondsLeft->setText(QString::number(secsLeft));
}
and finally main.cpp
#include "MainWindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I basically need help and an explanation on how I should use the QT Thread's controller/worker integrated in my GUI.
I'll try to answer all the issues you're addressing in your question:
I don't know how to get the controller or the worker to connect a signal from the thread to update this slot.
You got that almost right yourself.
Your Worker lives within the event loop of your Controller:
+--GUI-thread--+ (main event loop)
| MainWindow, |
| Controller --o-----> +--QThread--+ (own event loop in ::exec())
+--------------+ | Worker |
+-----------+
Communication between Controller and Worker must happen through signal-slot-connections. In between MainWindow and Controller signals help keep dependencies to a minimum.
You can imagine Controller as a kind of relay: Commands from MainWindow get forwarded through Controller to the Worker. Results from Worker get forwarded through the Controller to anyone who is interested.
For this, you can simply define signals in Controller:
class Controller : public QObject
{
//...
signals:
void SignalForwardResult(int result);
};
and then instead of
connect(worker, &Worker::resultReady, this, &Controller::handleResults);
use the new signal:
connect(worker, &Worker::resultReady, this, &Controller::SignalForwardResult);
// Yes, you can connect a signal to another signal the same way you would connect to a slot.
and in your MainWindow constructor:
//...
ui->setupUi(this);
connect(mpController, &Controller::SignalForwardResult, this, &MainWindow::displayResult);
Likewise for Worker::progressUpdate() -> Controller::SignalForwardProgress() -> MainWindow::updateValue().
how to stop and restart a replacement worker when the current one has either finished or been interrupted and restarted.
Either create a new worker for each task or use a persistent worker that can react on new task requests.
You start a task by sending it to the worker ::doWork() function.
A task ends by itself when the long work is finished. You get a notification via the worker's resultReady signal.
Cancelling a task is only possible by intervention
If you indeed have a QTimer, you can use a cancel() slot because that will be invoked in the thread's event loop before the next timeout.
If you have a long-running calculation, you need to share some token that you read from inside your calculation method and set from your GUI thread. I usually use a shared QAtomicInt pointer for that, but a shared bool usually suffices too.
Note that while a method is running on a thread, that thread's event loop is blocked and won't receive any signals until the method is finished.
DON'T use QCoreApplication::processEvents() except if you really know, what you're doing. (And expect that you don't!)
how to properly integrate the timer in my worker thread
You shouldn't.
I guess you use a background thread because there is so much work to do or you need to blocking wait for so long that it would block the GUI, right? (If not, consider not using threads, saves you a lot of headaches.)
If you need a timer, make it a member of Worker and set its parentObject to the Worker instance. This way, both will always have the same thread affinity. Then, connect it to a slot, like Worker::timeoutSlot(). There you can emit your finish signal.
I have been new to the Qt environment. I recently started with a QtCreator project for a simple chat application (QMainWindow). I have nearly completed the project but stuck with the SIGNAL/SLOT problem.
Let me explain my problem in brief :
Due to the length of the code I am not able to paste it here.
I have two classes MainWindow and NetworkFile.
The function newServerConn() in NetworkFile connects the signal readyRead() to the slot readFromClient().
The string returned by client is stored in a QString in readFromClient() SLOT.
Problem:
I have to return the QString in the slot to the newServerConn() function and from there to a function in MainWindow class because only then I would be able to print the string to the plainLineEdit widget pointed by the ui object.
Question 1:
How can I return a value from the slot?
Question 2:
Or is there any way I could get a copy of the ui instance in the NetworkFile class so that I could use the widgets from there?
Thanks.
I would just emit the data as a signal and wire up the connection between that new signal and a slot where you add then string to your ui.
A quick self-contained example (which btw. "Due to the length of the code I am not able to paste it here." is just an excuse, you can pretty much always cut down your relevant code)
Header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTextEdit>
class NetworkFile;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow(){}
public slots:
void addText(QString str)
{
edit->append(str);
}
private:
QTextEdit* edit;
NetworkFile* net;
};
class NetworkFile : public QObject
{
Q_OBJECT
public:
NetworkFile(QObject *parent = 0):
QObject(parent)
{
connect(&server, &QTcpServer::newConnection,
this, &NetworkFile::newConnection);
//TODO: check return value
server.listen(QHostAddress::Any,16001);
}
signals:
void dataRead(QString);
public slots:
void newConnection(){
//TODO: wire up socket disconnect with deleteLater, also check for null
QTcpSocket* socket = server.nextPendingConnection();
connect(socket, &QTcpSocket::readyRead,
this, &NetworkFile::dataAvailable);
}
void dataAvailable(){
//HACK: only for brevity, create a connection wrapper that contains the socket in real code
QTcpSocket* source = (QTcpSocket*)sender();
auto bytes = source->readAll();
if(bytes.size())
{
emit dataRead(QString(bytes));
}
}
private:
QTcpServer server;
};
#endif // MAINWINDOW_H
cpp file
#include "mainwindow.h"
#include <QApplication>
MainWindow::MainWindow(QWidget *parent ):
QMainWindow(parent)
{
edit = new QTextEdit(this);
net = new NetworkFile(this);
connect(net, &NetworkFile::dataRead,
this, &MainWindow::addText );
setCentralWidget(edit);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
As from the documentation:
Signals [...] can never have return types (i.e. use void).
Therefore slot return types are useless when invoked through a signal (even though you can still use them when you invoke a slot directly, ie if it's a member function).
That being said, you can capture ui or even better plainLineEdit by reference or by address in your slot (ie if it's a lambda) and set correctly the string from there.
I was wondering how I can run a function when closing the terminal (I'm on Linux) of my Qt Console Application. I have a 'static' class which holds all the variables I need (I know I can use singleton but I like this way better) and it has a function called destroy, this will delete all pointers).
So this is my .cpp of the 'static' class:
#include "engine.h"
logging* engine::m_logging;
tcp_listener* engine::m_tcp_listener;
void engine::initialize()
{
engine::m_logging = new logging();
engine::m_logging->write_line("Initializing Fullmoon Messenger server...");
engine::m_tcp_listener = new tcp_listener();
engine::m_tcp_listener->start("127.0.0.1", 30000);
}
void engine::destroy()
{
delete engine::m_logging;
}
logging* engine::get_logging()
{
return engine::m_logging;
}
And this is my main.cpp:
#include <QCoreApplication>
#include "engine.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
engine::initialize();
return a.exec();
}
How can I call engine::destroy when closing the application? I assume there's a signal for it.
You need to handle the POSIX signal SIGHUP for this.
(Note: POSIX signals are something completely different than Qt signals, so they're not handled with "slots". Don't confuse them.)
Note that your options for what to do in a POSIX signal handler are very limited. The man page signal(7) lists the functions which are safe to be called. In the comments to this answer, Kuba Ober pointed out that you should to stick to the official documentation for handling POSIX signals in Qt applications. But since the process as explained in the documentation is quite complicated, I wrapped it in a reusable class PosixSignalProxy, converting POSIX signals to Qt signals.
If you use this proxy class you just have to write:
PosixSignalProxy<SIGHUP> sighupProxy;
QObject::connect(&sighupProxy, &PosixSignalProxyBase::receivedSignal, []{
engine::destroy();
});
The class is found at the bottom of this post.
Note that only one instance of a PosixSignalProxy can be created for each POSIX signal type. If you need to do multiple things when receiving a signal, you can however connect to the Qt signal multiple times.
Also, you might be interested in similar signals for different external reasons for quitting your application, such as killing it or hitting Ctrl+C in the terminal window.
SIGHUP (as in the example above): when the terminal window was closed (and the parent process was destroyed)
SIGINT: when the user hits Ctrl+C - Note that when you handle this signal you need to quit at the end of the handler since your process is responsible of finally quitting itself. You overwrite this default behavior and have the option not to only cleanup stuff but also to ignore the user's wish to quit the application.
SIGTERM: when the process is killed with e.g. kill (not to be confused with SIGKILL which is a more aggressive way to kill a process; you can't handle that one)
Here is the class definition:
posixsignalproxy.h
#ifndef POSIXSIGNALPROXY_H
#define POSIXSIGNALPROXY_H
#include <QObject>
class QSocketNotifier;
typedef void (*PosixSignalHandlerType) (int);
// Helper base class (no template) - Do not use this class directly.
class PosixSignalProxyBase : public QObject
{
Q_OBJECT
public:
PosixSignalProxyBase(
QObject *parent,
int (&sockets)[2],
int posixSignalNumber,
PosixSignalHandlerType posixSignalHandler,
int posixSignalFlags);
~PosixSignalProxyBase();
signals:
/**
* Qt signal which is emitted right after receiving and handling the POSIX
* signal. In the Qt signal handler (slot) you are allowed to do anything.
*/
void receivedSignal();
protected:
static void staticSignalHandler(int (&sockets)[2]);
private slots:
void handleSignal();
private:
int (&sockets)[2];
QSocketNotifier *notifier;
};
// Actual proxy class, defining its own static proxy signal handler function and sockets.
template <int signum>
class PosixSignalProxy : public PosixSignalProxyBase
{
public:
PosixSignalProxy(QObject *parent = nullptr, int posixSignalFlags = 0) :
PosixSignalProxyBase(parent, mySockets, signum, &posixSignalHandler, posixSignalFlags)
{}
PosixSignalProxy(int posixSignalFlags) :
PosixSignalProxy(nullptr, posixSignalFlags)
{}
static void posixSignalHandler(int) {
PosixSignalProxyBase::staticSignalHandler(mySockets);
}
private:
static int mySockets[2];
};
template <int signum>
int PosixSignalProxy<signum>::mySockets[2];
#endif // POSIXSIGNALPROXY_H
posixsignalproxy.cpp
#include "posixsignalproxy.h"
#include <QSocketNotifier>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
PosixSignalProxyBase::PosixSignalProxyBase(QObject *parent, int (&sockets)[2], int posixSignalNumber, PosixSignalHandlerType posixSignalHandler, int posixSignalFlags) :
QObject(parent),
sockets(sockets)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockets))
qFatal("PosixSignalProxy: Couldn't create socket pair");
notifier = new QSocketNotifier(sockets[1], QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), this, SLOT(handleSignal()));
struct sigaction sa;
sa.sa_handler = posixSignalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = posixSignalFlags;
if (sigaction(posixSignalNumber, &sa, 0) > 0)
qFatal("PosixSignalProxy: Couldn't register POSIX signal handler");
}
PosixSignalProxyBase::~PosixSignalProxyBase()
{
delete notifier;
}
void PosixSignalProxyBase::staticSignalHandler(int (&sockets)[2])
{
char tmp = 1;
::write(sockets[0], &tmp, sizeof(tmp));
}
void PosixSignalProxyBase::handleSignal()
{
notifier->setEnabled(false);
char tmp;
::read(sockets[1], &tmp, sizeof(tmp));
// Here, we're allowed to do Qt stuff.
emit receivedSignal();
notifier->setEnabled(true);
}
You're looking for QCoreApplication::aboutToQuit if you want to use a signal.
Better idea IMO is for engine not to have static functions but to manage its resources properly in its destructor. You can make it a singleton if you want.
I try to create something like a window pool. You can use these windows everywhere in your program to display graphics and plot diagrams etc. The widgets working well but the main problem at the moment is the frustrated tries, to create the pool. One non QObject-Object should represent a QMainWindow to cut the bindings to Qt.
I cannot create a widget -> I tried invokeMethode, connect and QTimer but nothing works. Sometimes the methods don´t get called or I am not in the gui thread... Any idea?
Edit 2 - new version:
header:
#pragma once
#include <QMainWindow>
#include <QTimer>
class MyWindow : QObject
{
Q_OBJECT
public:
MyWindow();
};
class QWindowPool : public QObject
{
Q_OBJECT
public:
QWindowPool();
public slots:
void createWindow();
};
class QWindow : public QMainWindow
{
Q_OBJECT
};
cpp:
#include
#include <QApplication>
#include <QTimer>
#include <QtConcurrent/qtconcurrentrun.h>
#include <iostream>
#include <future>
static QWindowPool *pool = new QWindowPool();
QWindowPool::QWindowPool() {
// check if app is running
if (!QApplication::instance()) {
bool appOnline = false;
QtConcurrent::run([&appOnline](){
int c = 0;
new QApplication(c, NULL);
appOnline = true;
qApp->exec();
});
while (!appOnline) {}
}
moveToThread(QApplication::instance()->thread());
}
void QWindowPool::createWindow() {
printf("window created\n");
new QWindow();
}
MyWindow::MyWindow() {
QTimer::singleShot(0, pool, SLOT(createWindow()));
}
int main()
{
MyWindow mw;
std::thread t1([](){
MyWindow mw;
std::thread t2([](){
MyWindow mw;
});
t2.join();
});
t1.join();
std::cin.ignore();
return 0;
}
Now the code do what is should. I can create widgets in different threads. But there are two scenarios, where I would stack at:
Someone (anyone who would like to use this library) creates before me QApplication and never calls qApp->exec
Someone want to create an own UI with Widget but does not work in my qt::concurrent gui thread. He would probably not get along with this.
What I want is in the final application:
The user should get the possibility to write anywhere in his code and in any thread:
MyWindow mw(dataToDisplay)
and the window should be created and showed to him.
Qt will only let you create widgets from the main GUI thread, this is explicitly mentioned in the docs (emphasis mine):
As mentioned, each program has one thread when it is started. This
thread is called the "main thread" (also known as the "GUI thread" in
Qt applications). The Qt GUI must run in this thread. All widgets and
several related classes, for example QPixmap, don't work in secondary
threads. A secondary thread is commonly referred to as a "worker
thread" because it is used to offload processing work from the main
thread.