Qt Gui not updated because of threading issue - c++

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

Related

How to avoid freezing the user interface in a loop (minimal example) [duplicate]

My first naive at updating my progress bar was to include the following lines in my loop which is doing the processing, making something like this:
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
//Added these lines but they don't do anything
ui->progressBar->setValue(numberProcessed++);
ui->progressBar->repaint();
}
I thought adding the repaint() would make the execution pause while it updated the GUI, but apparently it's not that simple. After looking at the questions:
QProgressBar Error
Progress bar is not showing progress
it looks like I'm going to have to put the data processing in a different thread and then connect a signal from the data processing thread to the GUI thread to update the progressbar. I'm rather inexperienced with GUIs and threads and I was wondering if anyone could just point me in the right direction, ie what Qt classes should I be looking at using for this. I'd guess I need a QThread object but I've been looking through the QProgressBar documentation but it doesn't bring up the topic of threading.
As #rjh and #Georg have pointed out, there are essentially two different options:
Force processing of events using QApplication::processEvents(), OR
Create a thread that emits signals that can be used to update the progress bar
If you're doing any non-trivial processing, I'd recommend moving the processing to a thread.
The most important thing to know about threads is that except for the main GUI thread (which you don't start nor create), you can never update the GUI directly from within a thread.
The last parameter of QObject::connect() is a Qt::ConnectionType enum that by default takes into consideration whether threads are involved.
Thus, you should be able to create a simple subclass of QThread that does the processing:
class DataProcessingThread : public QThread
{
public:
void run();
signals:
void percentageComplete(int);
};
void MyThread::run()
{
while(data.hasMoreItems())
{
doSomeProcessing(data.nextItem())
emit percentageCompleted(computePercentageCompleted());
}
}
And then somewhere in your GUI code:
DataProcessingThread dataProcessor(/*data*/);
connect(dataProcessor, SIGNAL(percentageCompleted(int)), progressBar, SLOT(setValue(int));
dataProcessor.start();
You need to call QApplication::processEvents() periodically inside your processing loop to let it handle UI events.
As Georg says, Qt is a single-threaded co-operative multitasking environment. You get full control of your process until you relinquish it voluntarily with processEvents() - until you do that, Qt can't update the UI elements, handle async HTTP requests, handle input, or pretty much anything else. It's up to you to make sure that stuff gets a timeslice while you're in a long processing loop.
You can create a sub-class of QThread that emits a signal progressChanged, which you connect to the QProgressBar.
connect() makes the connections auto connections per default. That means that the signal-slot-mechanism already takes care of the threading issues for you, so you don't need to worry about that.

How to have Qt embedded into another app (non-blocking way)

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.

Qt5: How to repaint while doing a big calculation

I am writing a mathematical simulator in Qt5 and when I click a button, some heavy calculation needs to be done. During it, I want to display a Please, wait window, eventually with a progress bar. Preferably without using threads.
Problem is, during calculation the application hangs, events are not handled, and what should be a please, wait window is merely a window frame without any contents (looks transparent).
PC: AMD X2 L325, 2GB RAM, Radeon E4690
OS: Debian 6 (Squeeze, Old stable)
gcc 4.4.5, Qt 5.2.0
Any help would be appreciated!
While you could call QApplication::processEvents, it's not the best approach.
If you're avoiding threads because they're new to you, then I'm sure you'll find it much easier once you've done it once. Qt makes it easy.
All you need to do is create a class derived from QObject which will do the calculations. Next, create a thread and call the object's moveToThread function. The thread is then controlled with a few signals and slots. That's all there is to it.
Rather than repeat the content here, I suggest you read this article, which explains it in detail and provides clean and concise example code.
From the new object that processes your calculations, it can then emit a signal to a slot on the main thread, which will update the progress on your "Please Wait" window.
Note that Widgets and all rendering must be done on the main thread.
I prefer use Qt Concurrent. It is not well documented, but very handy, much better then using QThread directly.
I usually do such things like that I have separate QObject for logic, in there some slot which calls heavy calculation like that (see run documentation):
void MyCalculationClass::startCalculating() {
QtConcurent::run(this, &MyCalculationClass::doHeavyCalculation);
}
Where method doHeavyCalculation emits signals with progress and calculation results.
Usually this method operates on its own data not modified by other threads/methods, so if synchronization is needed, it is trivial. Signal-Slot mechanism is handling most of the multithreading issues (note that default connections detects that signals is emitted from other threads and queues slot calls in proper thread, it is done automatically by default).
i have such problem and i solve it like this, i make calculation in another thread( i use std::thread instad of QThread) before i start my calculation i just start timer
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(repaint()));
timer->start(1);
and then
std::thread t(&Widget::calcBackgound, this);
t.detach();
You can put the heavy and time consuming part of your code in run() member function of another class which inherits from QThread. After that create an instance of the new class and simply call its start() function.
Your new class can have a signal which emits the current progress value. you can then connect this signal to the slot of a progress bar.

Render off screen widget in a separate thread Qt

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.

qt threads worker design with blocking while loop

i using qt5 and opencv to create an application that give a user inteface using qt and does the image processing part in opencv.....
so far my design is:
i am displaying a video and some standard controls like buttons and checkboxes using qt main gui thread
for capturing image and processing it, i have created a worker class derived from QObject and moved it to a thread....
the function that is executed in the worker class(Worker::process) has a blocking while loop.....that constantly:
captures a frame from a video or a camera
does some processing on it
converts from cv::Mat to QImage
emit a signal to the main thread to display the QImage
also in order to recieve user input i was using emitting signal from the main thread to the worker slots
the problem i faced was that the signal from the main thread never got picked off by the worker because of the event loop blocking while loop.
after much searching i came up with the solution to use Qt::DirectConnection argument while connecting the signal from the main thread to the worker slots. that solved the problem at that time.
now i need to add a qtimer or qbasictimer inside the blocking while loop....and guess what, the timer slot(in the case of qtimer) and the protected timerEvent handler (in the case of the qbasictimer) never get called. my hunch is that again the blocking while loop is the culprit
after much searching and reading on forums i have come to the conclusion that somehow my over all design maybe incorrect.....and as i keep adding more functionality to my application these problems will keep showing up.
I have two options now:
somehow call the threads exec() function inside the blocking while loop. so the question to the gurus out there is:
"how do i call the thread::exec() method inside a worker QObject class, i need the reference to the thread running the worker to call exec()" (short term solution)
change the whole implementation.....and here the questions is:
"what are my options....." (long term)
please feel free to ask for details in case my wording or english has made the problem unclear in any way.....thanks...
Inside your worker's blocking loop, call qApp->processEvents(); periodically.
http://qt-project.org/doc/qt-5.1/qtcore/qcoreapplication.html#processEvents
#include <QApplication>
// ...
void Worker::doWork()
{
while(true)
{
someLongImageProcessingFunction();
qApp->processEvents();
}
}
This should allow for the slots to get processed, and for the timers to update.
Using a direct connection may let you access and change values local to your worker, but you should be careful about thread safety. If you put a QMutexLocker right before your values that get modified by your GUI and right before your worker thread uses them, you should be good.
http://qt-project.org/doc/qt-5.1/qtcore/qmutexlocker.html
Also if you wanted any of those slots to run on the worker thread, you need to use the QueuedConnection.
http://qt-project.org/doc/qt-5.1/qtcore/threads.html
http://qt-project.org/doc/qt-5.1/qtcore/qthread.html#details
In some parts of the Qt docs it describes subclassing the QThread class. Other parts recommend the Worker/Producer model, and just use connections to setup how you use your threads. Usually there are fewer gotchas with the Worker/Producer model.
Hope that helps.