Multiple Threads, how to create qt widgets properly - c++

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.

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.

use QGridLayout::addWidget with mutythread

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.

Update QT Graphicview from other Thread

i am at the moment really confused about threading in QT. I read so much different opinions which i can realize this.
I have a class (Computations) which do heavy computations and generate a lot of solution. When this class find a solution i call with help of
boost::function<void (Solution)> f;
a custom function. Which can be bind with
f = boost::bind( &MainWindow::FoundSolution, this,_1);
No i have my mainwindow in QT. There i call my class Computations with
Computations comp(f);
QFuture<void> future = QtConcurrent::run(comp,&Computations::DoSomethink);
So it compute while i can use the GUI and i get the response of new solutions to the FoundSolution function in my mainwindow. In this function I use QGraphicview to draw my solution. The Qgraphicsview is a member of my Mainwindow.
This works sometimes.
But i often get the following error
Assert failure in QCOREApplication::SendEvent: " cannot send events to
objects owend by a different thread. Current thread 438bc40. Receiver
" (of type "Qgraphicsscene) was created in thread 15dcc00, file
kernel\qcoreapllication line 494
This mean i call my GUI application from a thread which is not the main and this is forbidden by QT. But with my boost bind i should be in my main thread or? And why it works sometimes ?
Do you know a better implementation for this? I am really new with QT and threads.
Thank you for your help.
If you emit a signal from you worker thread that is connected to a slot of an object that lives in the ui thread, the slot will be executed in the ui thread.
So basically if you want to draw a new point in the QGraphicsView, send a signal from your worker thread passing in the coordinates of the new point to draw. The signal need to be connected to an object that lives in the ui thread. The slot will then handle drawing the new point in the QGraphicsView which will work since the slot is executed in the ui thread.
For more information see Signals and Slots Across Threads
The normal way to do this is to use signals and slots. You can find some documentation, which is specific to your problem, here: Qt 4.8, Qt 5.
connect( &sender, SIGNAL(), &receiver, SLOT(), Qt::QueuedConnection)
The easier fix is to add Qt::QueuedConnection to the problematic slot connection call.

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.

Setting common parent Qt widget for new widget in separate thread

I need to create a widget in a separate thread and to set MainWindow for it as a parent widget. Creation of a thread cannot be avoided.
In the constructor of a new widget I am specifying a pointer to MainWindow, but give
QObject::setParent: Cannot set parent, new parent is in a different thread
How to solve this?
P.S. Child widgets may be numerous.
You cannot create UI widgets outside of main thread
This is not possible. See the following code reference for details why not:
QObject source code
In particular, you would need to pay attention to this warning:
"qWarning("QObject::setParent: Cannot set parent, new parent is in a different thread");"
which you got on the command line based on your question, so this is all expected.
As the warning says, you need to make sure that the parenting happens in the same thread between the parent and child.
Creation of a thread cannot be avoided. How to solve this?
I am afraid you will need to refactor the code by either moveing this out of your thread into the same where the parent is or/and not have the separate thread at all.
Based on the information in your question, currently, it is not possible to say more since we do not yet completely know the functionality of your other thread.
Hope this helps with explaining it.