Pass QTableView model to another thread and operate with it - c++

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?)

Related

Multiple Threads, how to create qt widgets properly

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.

QListView setModel problems calling via QMetaObject::invoke

Hi I have a QListView widget displayed correctly on my user interface.
I am registering a callback to a completely separate 3rd party library. This callback will be called on a completely separate thread to my user interface. I need this callback to interact with the QListView widget and set a new data model, so I believe I have to use
MyDataModel * model = new MyDataModel( ui->listViewWidget );
QMetaObject::invokeMethod( ui->listViewWidget, "setModel", Q_ARG( MyDataModel *, model ) );
However, It doesn't seem to work. i.e. no data is presented in the QListView widget. I've debugged the return value from QMetaObject::invokeMethod and it's returning false which suggests there's no method called "setModel" on the QListView. However, when I arrange for the callback to be called via the user interface thread, i.e. through a pushbutton on_clicked() event and make a call to
MyDataModel * model = new MyDataModel( ui->listViewWidget );
ui->listViewWidget->setModel( model );
This works perfectly, so there is a "setModel" method on the QListView..
Can someone please help me understand why QMetaObject::invokeMethod isn't working and maybe clear up wether I need to call invokeMethod in this way. i.e. are my thread assumptions correct about it needing to be ran on the event loop thread.
Yours, dazed and confused..
Mark.
The method QMetaObject::invokeMethod invokes only slot or signal on the object. Therefore your setModel must declared as slot. Also Q_ARG() takes a type name and a const reference of that type.

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.

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.

Qt - How to create widget asynchronously?

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.