qtthreadpoolsignals-slotsqmodelindex

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 QThreadPool) 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.


Solution

  • 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