Passing QModelIndex cross Thread queued connection
WMIQuery::wmiquery(WMI::WMITable* table, const QString& query, WMI::ProgressIndicator* progressIndicator)
This is the Function signature. and I am calling it through QtConcurrent::run
QFuture<quint32> future = QtConcurrent::run(WMI::WMIQuery::wmiquery, _table, query);
The architecture is quite simple.
Expected number of rows that will be returned by the query is known.
query is ran parallelly and on each record fetch a row is added to table: WMI::WMITable*
WMI::WMITable
is a Simple QObject Table Data Structure .
it emits rowsAboutToBeInserted(QModelIndex, int, int)
and rowsInserted(QModelIndex, int, int)
upon row addition.
On the other hand ProgressIndicator
in instantiated on main thread and the table
is passed to its ctor
. it gets the expected total number of rows from WMI::WMIQuery::wmiquery()
through ProgressIndicator::setRecordCount(quint64 count)
.
it has a slot rowAdded()
which emits the progress out of 100 by doing some simple mathematics. In its ctor it connects
connect(_table, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowAdded()));
What I think. as WMI::WMIQuery::wmiquery()
i running on a different thread (on QThreadPo开发者_Python百科ol
) this connection is a cross thread queued connection . am I correct ?
I am getting the following error at runtime
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registered using qRegisterMetaType().)
What should I do ? as my SLOT(rowAdded())
does not require the 3 arguments of SIGNAL(rowsInserted(QModelIndex,int,int))
should I make another signal like rowInserted()
and emit it whenever I am emitting rowsInserted(QModelIndex,int,int)
and use this SIGNAL
instead for this coinnection
You may ask why I am using model like signals like rowsInserted(QModelIndex,int,int)
in the table data structure. cause I do also have a model that is connected to this table. which will also be updated row by row. however I think that is immater in this regard.
Before emitting a signal across a thread boundary with a non-trivial argument type (like QModelIndex
), you must first call this:
qRegisterMetaType<QModelIndex>("QModelIndex");
That prepares Qt to be able to emit the signal across a thread boundary.
Normally you would do this in main()
or somewhere that only runs once, before calling emit
, but after your QApplication
has been instantiated.
This is only necessary for types that are non-trivial. For example, a signal like this would not require you to call qRegisterMetaType()
signals: void mySignal(int foo, int bar);
But a signal like this does require qRegisterMetaType()
:
signals: void mySignal(QModelIndex);
For more info, see the Qt docs here: http://doc.qt.nokia.com/latest/qmetatype.html#qRegisterMetaType
I know this is rather late, but I wanted to be sure someone mentioned it: QModelIndex is not meant to be queued, for the same reason that it's not meant to be stored and used later in other ways. That is, if the model changes before you use the QModelIndex, you will get undefined behavior. If you need queued events with model indices, you should probably use QPersistentModelIndex. Not really relevant to the original question, but may be of use to someone who lands here.
精彩评论