The application I'm working on is made of many C threads communicating together via messages (0mq). One of these threads is handling the display and should render off screen a widget in order to communicate its "screenshot" to other threads of the application.
The thing is that in order to paint a widget, you need to place it in a QApplication and call the exec() method of the QApplication, which is essentially a loop. So my thread is then completely stuck and can't communicate with the outside world anymore since it's in the exec() method.
Is there a way I can launch the QApplication in a separate thread and communicate with it so my display thread doesn't get stuck?
Or is there at least a way to do what I want to do with Qt?
Thanks a lot !
Edit: This application will eventually be a Qt Embedded Application
Update Basically, my question is : how to start a QApplication in a separate thread from my C code and communicate with it?
I ended up creating a separate thread for the QApplication main event loop (exec()) and used 0mq sockets to communicate with it from the rest of my application.
I don't understand what do you mean by "paint a widget". But be aware: QWidget is a part of GUI and GUI parts should be touched by Main(UI) thread only. It is a rule you can't change. Moreover QApplication works on Main thread only since QApplication is the main part of the GUI itself.
You can post messages to QAppplication by using global qApp object(you need to include QApplication for it) and sendEvent() or postEvent() methods.
Also I'd suggest you to generate QImage with whatever data you have and propagate it via aforementioned event mechanism to the widget you need. But, obviously, I don't know what you really need.
Related
I am using a 3D rendering C++ API and want to use Qt to display GUIs on top of it.
My rendering API runs in the main() application thread, just like Qt wants.
At first I tried to run Qt in it's own std::thread and it worked perfectly fine - and I have no idea what Qt's doc means with
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
https://doc.qt.io/qt-5/thread-basics.html
This is either plain wrong or poorly written...
My std::thread worker looks something like this:
int SomeClass::qt_app_worker(size_t width, size_t height, const std::string& title, const std::string& contents) {
int argc = 0;
QApplication app(argc, NULL);
// QDialog here
return app.exec();
}
The problem is then I can't do anything with this Qt app because if I try to create say another QDialog from the main() thread, Qt will complain I can only do this from the thread owning my QApplication (qt_app_worker).
So I'm either permanently locked out of the qt_app_worker thread, or I have to implement my own message queue for EVERYTHING Qt-related.
I sketched it with a derived QApplication class using startTimer() and then handling custom messages in timerEvent(...) but this is just too much hassle.
I just don't understand why Qt won't let a user run it in a separate thread, hopefully I'm just missing something.
There are (at least) two built-in thread-safe ways to communicate with the GUI thread (which is usually the "main thread" of Qt application, which is why it is often called main thread, and for Qt point of view it is).
You can post events (including your own custom event subclasses) to the thread using QCoreApplication::postEvent.
You can invoke methods of objects in another thread, provided you do so with Qt::QueuedConnection or Qt::BlockingQueuedConnection connection type using QMetaObject::invokeMethod (and its different overloads).
Communication the other way, from Qt to you own main thread, can happen in a few ways. I believe using Qt::BlockingQueuedConnection also allow getting a return value, but you probably don't want that blocking.... So you can just use any of the usual methods of communicating between threads, not limited by Qt, such as simply atomic or mutex-protected variables which are set from Qt, and your threads polls or otherwise reads when relevant (such as at start of every frame). Or make a simple message queue, if you want to be able to track every change and not just the state at the start of a frame or whatever.
I have the follow constellation:
A qt gui thread with MainWindow
Another thread which essentially is a CameraManager...everytime a camera is added/removed the MainWindow will be informed.
It roughly looks like this:
Mainwindow derives from ICameraAddedConsumer
MainWindow implements ConsumeCameraAdded and creates widget inside this function. It subscribes itselv as a consumer to the CameraManager
CameraManager calls ConsumeCameraAdded of all it's consumers (MainWindow) when a new camera is added.
The problem is that CameraManager lives in a different thread and Qt will obviously complain about this since a widget is not created in the same thread as the mainwindow was.
Any suggestions how I can solve this?
As per comments, using signals/slots between QObjects in different threads should take care of the issue "automagically."
Barring that, and assuming MainWindow/ICameraAddedConsumer is a QObject, one idea could be to use something like:
QMetaObject::invokeMethod(consumer, "ConsumeCameraAdded", Qt::QueuedConnection, ...)
where consumer is a pointer to the MainWindow/ICameraAddedConsumer instance.
There's QWaitCondition but I'm not sure that makes sense in this case (though it could be adapted I suppose).
Otherwise... don't create the widget in ConsumeCameraAdded() but set some flag there (and return) and then use a QTimer or QObject::timerEvent() to periodically check the flag and create widget if it is set. Unfortunately I'm pretty sure you will not be able to create or start a timer within ConsumeCameraAdded() itself because of threading issues.
Since creating widgets takes a lot of time, I try to create widgets in different threads and add them to the main layout, but that fails. When creating widgets and then adding them sequentially, the program works normally. Notifications I received: "QObject::setParent: Cannot set parent, new parent is in a different thread"
Is there a way to do it?
No, there is no way to do it.
Qt GUI classes including QWidget must be used only from the main thread.
Quoting Qt documentation:
Although QObject is reentrant, the GUI classes, notably QWidget and
all its subclasses, are not reentrant. They can only be used from the
main thread. As noted earlier, QCoreApplication::exec() must also be
called from that thread.
This is enforced in Qt code by a Q_ASSERT_X when you construct a QWidget:
Q_ASSERT_X(q->thread() == qApp->thread(), "QWidget",
"Widgets must be created in the GUI thread.");
So, even if you would find some work around to make it work, you would not have any guarantee that your code will work in a reproducible way and that any Qt update will not break your code.
Regarding your specific problem, creating widgets should not be time consuming. I can think of 2 reasons why it would be time consuming:
Your widgets are doing heavy computation when you create them. Then you shoul put the computation, and only the computation, in another thread.
You are creating a lot of widgets in one shot. The you can deffer the creation using the event loop. Basically, you create some widgets then post an event or set a timer that will create some more widget, etc. until you meet some stop conditions.
I am using a third party library which takes 60-90 seconds to dynamically load several libraries. It is an unfortunate design choice, but I can't change who the built their code.
I am trying to use a QSplashScreen to at least tell the user to wait while I'm doing this one-time loading in the background. The problem is that the splash screen is not painting. I can see a window of non-painted space while the library loads. I can see the splash screen afterwards before I close it.
I looked at similar questions (e.g. Qt Splash Screen not showing) but nothing seems to resolve my problem. I have tried loading an empty QPixmap and just giving it a solid color. That doesn't show up either.
QApplication a(argc, argv);
QPixmap pxl("icon.bmp");
QSplashScreen qss(pxl);
qss.show();
qss.showMessage(QString::fromStdString("Please wait... Loading"));
a.processEvents();
MainWindow w;
//thread is blocked
w.preLoad();//this is where the lengthy process takes place
w.show();
qss.finish(&w);
I'd like to ensure that it at least paints once before I start my loading process.
------------------------EDIT-------------------------------
Let me reiterated that the call to preLoad is BLOCKING the thread. This is not an option. I have tried a separate thread for that process. I have tried with a separate thread for the splash screen as well (turning it on and then finishing whne the other thread is done). I have tried using semaphore between the two threads to accomplish this and while everything works (including the splash screen) it takes 200-800 seconds to load. That is simply not acceptable. Thus I would like to see if there is away around it from this perspective.
-------------------------Final solution--------------------------------
Thanks to the comments below I was made aware that Qt has its own threading functionality. All the problems I was seeing appear to be caused by the interplay of std::thread and Qt's own implementation.
I have a partial solution which does work. It's not as neat as it could be, but I wanted to include it in the question thread.
//in the main method code described above
MainWindow w;
w.preLoad();
while(w.IsLoading())
{
//waiting on semaphore signaling loading is complete
//this part could probably be done better with QThread
//and signals, but it is a quick fix for now
std::this_thread::sleepfor(std::chrono::milliseconds(500));
a.processEvents();
}
w.show();
qss.finish(&w);
//In the MainWindow class
void MainWindow::preLoad()
{
loading=true;//semaphore to stall main thread
QFuture<void> future = QtConcurrent::run(this, &MainWindow::LongMethod);
}
void MainWindow::LongMethod()
{
thirdPartyLibrary.impossibleCall();
loading=false;//this handles my semaphore
}
Every GUI is executed in an infinite loop, so Qt also uses it, but the blocking tasks generate that the loop is not executed correctly, showing inadequate behaviors like the one you observe.
If one wants to execute blocking tasks it is advisable to execute it in another thread for it Qt provides several possibilities:
QThread
QThreadPool and QRunnable
QtConcurrent
I recommend the following link for you to choose the right option for your case.
If you want to update the GUI view with the information generated in another thread it is advisable to use signals and slots, or use QtConcurrent.
GUI Thread and Worker Thread
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.
Another way is to force the GUI to update for this we can use qApp->processEvents().
References:
http://doc.qt.io/qt-5/thread-basics.html
http://doc.qt.io/qt-5/threads-technologies.html
I'm kind of stuck on something; regarding spawning multiple forms in OOP.
The message loop most of the time is (wxWidget's case) window->show();
bool MyApp::OnInit()
{
MainWindow *oWindow = new MainWindow(wxT("My Window"));
oWindow->Show(true);
return true;
}
Others have oWindow->run(), but anyway my question is:
I've created a second thread with the exact same structure of the function above and called the message loop method. The problem is that the window appears and dissapears suddenly which doesn't make sense to me. If however I call:
MainWindow *oWindow = new MainWindow(wxT("My Window"));
oWindow->Show(true);
MainWindow *oWindow2 = new MainWindow(wxT("My Window"));
oWindow2->Show(true);
It will work, but I don't want that as I will need to keep track of the windows I create and have them on separate threads. What can I do?
You cannot run wxWidgets windows in anything other than the main thread.
"GUI calls, such as those to a wxWindow or wxBitmap are explicitly not safe at all in secondary threads and could end your application prematurely. This is due to several reasons, including the underlying native API and the fact that wxThread does not run a GUI event loop similar to other APIs as MFC."
http://docs.wxwidgets.org/2.8/wx_wxthread.html
BTW, I cannot imagine any situation where what you want to do is a good idea. There is never any need to tun windows in more than one thread.
A windows program is event-driven. You can as have as many top level windows as you want, but there should be just one event queue so that the events on two windows do not end up in contention for the same resource. This is why wxWidgets prevents you trying to create two threads both handling windows events.