Qt - How to create widget asynchronously? - c++

I would like to create a widget in asynchronously and then assign it to a dialog in the main thread. I have a functions to create the widget:
shared_ptr<QTableWidget> createTable() {
auto table = make_shared<QTableWidget>()
// ... add some items to the table
return table;
}
When I call this function synchronously everything works as expected. Problem is when I call this function asynchronously:
auto futureWidget = QtConcurrent::run(createWidget);
I use QFutureWatcher::finished() signal and when the widget creation is done, I try to add that widget to the dialog in the main/GUI thread.
The problem is that sometimes it just crashes with SIGSEG when I add an item to the table. Sometimes when it completes the created widget is not shown. Also there is a lot of warnings on the standard output about using pixmap outside GUI thread.
Is that not possible to create widgets in different thread in Qt? If it is possible, how to do it?

No, it is only possible to create GUI widgets within the main thread.
Usually, it does not take much time to create GUI part of widget. If you have some operation, that takes a lot of time, you probably should extract it from process of widget creation, process it in separate thread and then pass result of this operation to the newly created widget.
EDIT
If you have some complex tables in the widget, you should use Qt MVC system, i.e. QTableView and model based on QAbstractTableModel. You can then fill model in another thread and only then assign it to view, created in main thread.

Related

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.

Pass QTableView model to another thread and operate with it

I'm stuck at a learning project.
I've subclassed QObject, and set up a signal to work with a QAbstractItemModel derived object.
I see like I "received" the object passed in the signal from the GUI thread, and qDebug-ing it shows it holds the same address, however, when I try to modify the data in it through setData in the separated thread, the program crashes.
What can I do to "modify" this QTableView model from another thread?
Or should I create a new model in the thread and pass it back to GUI thread? (is this possible, if yes, how so?)

How can we make QTableWidget accessible from multiple threads and placing QPushButtons in a cell from another thread.?

I am new in Qt.I have a QTableWidget which is suppose to get continuous data from different threads of RTI DDS subscriber.I was using setUpdatesEnabled() property of the QTableview for updating values from another class.
But it also blocks the QTableWidget for in-between operations like selecting another row and whenever i try to add QPushButton in a certain column of QTableWidget with the help of setCellWidget(),it is making a separate PushButton instead of placing it inside that cell.
As commented, you should do no GUI update from anywhere but the main thread. So use a signal/slot connection to go back from a worker thread to the main thread and then do the GUI update (emit the signal from the worker thread and make sure the slot is being executed from the main thread, this should behave like this with default connection). Be careful to the lifetime of the variables passed to the emited signal if slot is executed through a Qt::QueuedConnection.
Then, for your QPushButton not being in the cell. Make sure its parent is the QTableWidget upon creation (but I doubt this is really mandatory because I expect QTableWidget will make itself parent of the widget when setCellWidget is called).
It's hard to hep more with no code being posted in the OP.

Qt Drag and Drop QTreeView

My TreeView has various folder with children. each child has a icon and text-name. the user can select one or more item and drag them into QMDI area. as image for my darg drop i have a local picture drag->setPixmap(QPixmap(myPixImage)). What I need is: how i make the selected item with icon and text as myPixImage dynamically.
It's easy to set the pixmap when your own code create the QDrag object, however using QXxxViews (not only QTreeView) you have only control on the QMimeData (when overriding QAbstractItemModel::mimeData()).
Therefore if you really need that, the only way I now is to subclass QTreeView, overriding (well... reimplenting) mouseMoveEvent() and the like.
If you do so, you can get the selected items when creating the QDrag through e.g. selectionModel()->selectedItems().
First of all: there's no simple way to do this. Basically because QDrag::exec is started when you (as developer) allow the start of the drag (example here) and it doesn't return until the drag is finished.
You want to change your QDrag object while dragging.
Your best option here is:
After creating the Drag object and before running QDrag::exec store the object in some pool that can be accessed anywhere in the code. Probably something like static map<QDrag *> pool
Set up a recurrent QTimer event that constantly updates the the QDrag object, which can be obtained from the pool. Do not try using Qthreads as you'll end up with some "QObject can't be moved from/to thread" error.
When the drag's ended (as user), clean up the object from the pool
Do mind that you'll have to visually tune the QTimer repeated events accordingly.

QT Creating many complex widgets

I have a QT application that allows a user to define a list of models. Each model defined has a fairly complex widget class that is created. Currently this is all being done in the main (GUI) thread. The program works fine for normal use, but I tried to stress test it by creating 200 to 1000 models and the creation of the GUI took a VERY long time (20 seconds to many minutes).
I tried a couple attempts at threading out the work using QtConcurrent::run, but the program always complained because "Widgets must be created in the GUI thread."
I found this answer on SO: How do I create a Window in different QT threads?. But this doesn't seem to be doing much in the new thread except telling the main thread to create a new widget. This does not distribute the workload, as far as I can tell.
With all of that, I have a couple direct questions:
1) Is there a better design (faster performance) than looping through my list of models and serially creating each widget?
2) If this process is possible to be multithreaded, can someone point me in the direction of a simple example?
There really is no way to put widget stuff to other threads. OpenGL rendering or some data processing for a widget to show when ready, stuff like that can easily use other thread, but not the actual widgets.
Better design would be to create the widget when you need it. Or just have one widget and update the data it displays (unless widgets for different items are actually different).
If you are worried about performance when scrolling, then one solution to that is to switch widget only after current one has been visible for some minimum time (say, 500ms if user keeps scrolling, or 200ms after last scroll event, some logic like that) note that this is not delay for reacting to user selection, this is delay after selection and visible widget change, so if user just changes to next item, GUI is updated immediately. But in scrolling the widget is not updated for every item briefly selected, and things don't slow down. Use QTimer or two to send signal when widget should be updated.