PDA

View Full Version : new QWidget in separate thread



magland
6th February 2008, 20:43
I create a "new QWidget" in a separate thread. When that thread ends, my widget gets deleted. How can I fix this problem?

marcel
6th February 2008, 20:48
Do you actually create a QWidget in another thread? Or was that just a figure of speech?
From "Threading support in Qt":


In practice, the impossibility of using GUI classes in other threads than the main thread can easily be worked around by putting time-consuming operations in a separate worker thread and displaying the results on screen in the main thread when the worker thread is finished. This is the approach used for implementing the Mandelbrot and the Blocking Fortune Client example.
So, creating widgets outside the GUI thread is out of the question.
What are you trying to do? There must be another solution.

EDIT:
I think a more relevant quote is:


Although QObject (http://www.qtcentre.org/forum/qobject.html) is reentrant, the GUI classes, notably QWidget (http://www.qtcentre.org/forum/qwidget.html) and all its subclasses, are not reentrant. They can only be used from the main thread

magland
6th February 2008, 20:55
Do you actually create a QWidget in another thread? Or was that just a figure of speech?
From "Threading support in Qt":
So, creating widgets outside the GUI thread is out of the question.
What are you trying to do? There must be another solution.

For example, I want to run the following "ChainLink script" in a separate thread:



tab=QTabWidget;
for j=1:10;
X=QWidget;
addTab(tab,X,'testing '+toString(j));
end;


ChainLink works fine in one thread, but now I want to execute all scripts in a separate thread, so that the main GUI (console) can continue responding. I am running into trouble because the widgets all disappear when the thread ends.

marcel
6th February 2008, 21:05
Unfortunately, I am not familiar to ChainLink. How do you run that script? I assume thre must be some kind of interpreter involved...

magland
6th February 2008, 21:10
Unfortunately, I am not familiar to ChainLink. How do you run that script? I assume thre must be some kind of interpreter involved...

Yes... I parse the script and create a syntax tree. Then I execute that syntax tree... each function in the tree comes from a plugin library. One of the functions (in a plugin library) looks like this:



bool QWidget2(QWidgetPtr &ret) {
ret=new QWidget;
ret->showNormal();
ret->setAttribute(Qt::WA_DeleteOnClose);
return true;
}


Everything is fine. But, as I said, what if I want to execute the syntax tree in a separate thread... perhaps you have some idea.

wysota
6th February 2008, 21:19
Forget about using widgets in worker threads. You'll need to create the widget in the main thread and communicate with it from the other thread using signals and slots or custom events.

marcel
6th February 2008, 21:19
Everything is fine. But, as I said, what if I want to execute the syntax tree in a separate thread... perhaps you have some idea.

Absolutely not... It seems to me that the syntax tree is by design made to not work in other threads.
I see it as a widget factory. This is common in projects where widgets are created dynamically. But widget creation should never be designed to require another thread.
You should keep the syntax tree in the main thread. How much does it take for it to parse a script and build the widgets?
For example the designer just blocks a bit when loading very complex UI files...

Regards

marcel
6th February 2008, 21:20
Forget about using widgets in worker threads. You'll need to create the widget in the main thread and communicate with it from the other thread using signals and slots or custom events.
No, he just wants to create the widgets from another thread, not to communicate with them.

wysota
6th February 2008, 21:30
You can always chop a lengthy process into chunks and execute one chunk at a time and process events in between.

marcel
6th February 2008, 21:49
But this means he must modify his ChainLink component, to make it expose smaller steps.

wysota
6th February 2008, 23:15
He is the one who wrote ChainLink, so I don't think this will be a problem :)

magland
7th February 2008, 00:44
Thanks for the discussion. I have thought of a solution that I am happy with. Just one more question (see end of post).

ChainLink scripts consist mostly of non-GUI numerical manipulations (like Matlab programs), so they do deserve to be executed in a work thread. However, it is clear based on your comments that creation of widgets within a separate work thread is out of the question. This is a problem since ChainLink has functions to create plots and graphs. Nevertheless, as pointed out in this thread, creating/manipulating widgets does not take much time (as compared with intense numerical computations). Therefore, a hybrid solution should be possible.

So here is what I plan to do:

1. As part of function definition, the user must identify which plugin functions must be executed in the GUI thread.

2. When the work thread encounters a syntax tree node containing a "GUI function", the thread pauses, and a signal is emitted: pleaseExecuteThisNodeInTheGuiThread().

3. When the GUI thread receives this signal, he executes the appropriate node, and sends back a signal: theRequestedNodeHasBeenExecuted(bool success).

4. When the work thread receives this signal, it resumes its work.

Now, my question is: what is the best way for a thread to pause until a signal is received.

Thanks!

magland
7th February 2008, 02:55
Okay I got it working. I used QWaitCondition, and now it works beautifully.

Basically, I execute the syntax tree in a separate thread. Whenever I need to execute a GUI function, I send control back to the main GUI thread using a signal/slot connection, and a QWaitCondition for the response. Now I see how a thread can effectively execute a GUI function in the main thread.

wysota
7th February 2008, 09:49
Now, my question is: what is the best way for a thread to pause until a signal is received.

There are two nice possibilities. One is to use custom events instead of signals and use sendEvent() instead of postEvent(). This should make the sending thread block until the event is processed. The other solution is to use blocking signal connections. See the description of QObject::connect() and the description of Qt::BlockingQueuedConnection which you should use. Your code will be much cleaner than when using wait conditions.

magland
7th February 2008, 12:07
There are two nice possibilities. One is to use custom events instead of signals and use sendEvent() instead of postEvent(). This should make the sending thread block until the event is processed. The other solution is to use blocking signal connections. See the description of QObject::connect() and the description of Qt::BlockingQueuedConnection which you should use. Your code will be much cleaner than when using wait conditions.


I am now using Qt::BlockingQueuedConnection as you suggest, and indeed the code is cleaner. Thanks!

There is one thing I am concerned about (although it doesn't seem to be a problem based on some trials). I don't want the thread to resume execution until AFTER the slot has been processed. With Qt::BlockingQueuedConnection, the thread is blocked until the signal is delivered... but is it safe to assume that the slot will be processed before unblocking?

wysota
7th February 2008, 12:32
Yes. That's the whole point. At least I think so :)