PDA

View Full Version : QObject::connect: Cannot queue arguments of type 'QModelIndex'



borges
6th September 2007, 11:53
Hello all,
i am porting a python application from qt3 to qt4 but i have some problem. Here is a minimal program showing the error i'm getting:



import sys,thread
from PyQt4 import QtGui, QtCore

app = QtGui.QApplication(sys.argv)
win = QtGui.QMainWindow()
table = QtGui.QTableWidget(1, 2)
win.setCentralWidget(table)
def change_row_count():
table.setRowCount(2)
thread.start_new_thread(change_row_count, ())
win.show()
app.exec_()


and this is what i get (under linux):
$ python test.py
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registed using qRegisterMetaType().)

changing rowCount in the main thread or commenting out setRowCount call in change_row_count() makes those errors disappear.

What's wrong?

Thanks in advance

marcel
6th September 2007, 12:02
Yes. Seems like QModelIndex is not known to QMetaType, which is weird, because there are Qt signals that pass QModelIndex parameters.

Try using qRegisterMetatType<QModelIndex>("QModelIndex") somewhere before connecting.

Regards

jpn
6th September 2007, 12:42
You should not touch GUI in a worker thread. The GUI classes, notably QWidget and all its subclasses, are not reentrant. They can only be used from the main thread. QModelIndex is not registered because it should not be passed as a parameter in queued signals.

borges
7th September 2007, 11:23
Thanks all.

what i need is to fill the table with the results of a long computation without freezing the gui while processing. What's the simplest way to achieve this?

since you warned me that only the main thread should touch the gui, i would create a working thread to update a shared variable (locked by a mutex) and then emit a signal when finished. the gui (main) thread would then call a slot to display data in the table.
i am a newbie at threads, so is this correct? is there something else i should take care of?

marcel
7th September 2007, 11:26
Yes that is correct. You can either hold a global data structure to store intermediary computations or you can do everything in the thread and at the end emit a signal with this data as parameter(s).

Regards

borges
21st September 2007, 13:34
Yes that is correct. You can either hold a global data structure to store intermediary computations or you can do everything in the thread and at the end emit a signal with this data as parameter(s).

Regards

Only one last question: if i use your solution (i.e. emitting a signal with my data as a parameter) and all interthread communication happens only using that emitted data, i don't need any mutex, right?
I mean, if i press two times a button to process data, the signal would be emitted two times, but since the connected slot is in the main program (which alters the table) the two slots are executed sequentially. Correct?

Thanks again

marcel
21st September 2007, 13:51
Only one last question: if i use your solution (i.e. emitting a signal with my data as a parameter) and all interthread communication happens only using that emitted data, i don't need any mutex, right?
I mean, if i press two times a button to process data, the signal would be emitted two times, but since the connected slot is in the main program (which alters the table) the two slots are executed sequentially. Correct?

Not really. Sending the event twice causes to events(QEvent) to be posted in the GUI's event queue. It will handle them asynchronously, so you are not guaranteed the event for the first button press gets handled first(but that's only if order matters to you).

The problem is that your worker thread could corrupt the static data while the GUI is processing the first event(thus reading data).

So I think the best solution is not to have only a data structure, but a stack of these data structures. The worker thread pushes new data in the stack while the GUI thread pops data from the stack.
So the GUI thread should check the stack periodically, to see if something new has arrived. You could implement this very easy with a QTimer, with a 200-300 msec delay.

So pressing the button just causes the worker thread to add data to the stack.