Solved QObject::connect: Cannot queue arguments message
-
I'm getting this message in the application output pane in Qt Creator running Qt 5.9 under OSX 10.12.5.
QObject::connect: Cannot queue arguments of type 'QVector<int>'
(Make sure 'QVector<int>' is registered using qRegisterMetaType().)My application is an image viewer. When a new folder is selected I load the thumbnails and file information into a QListView in a separate thread. In the thread any reference to item->setData triggers the message, but only for the first occurrence in the model. Further use of item->setData does not trigger a message.
I've created a bare bones test app that reproduces this behaviour:
mainwindow.cpp
#include "mainwindow.h MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { QStandardItemModel *lvModel = new QStandardItemModel; static QStandardItem *item; for (int i = 0; i < 3; ++i) { item = new QStandardItem(); item->setData(i, Qt::DisplayRole); lvModel->appendRow(item); } TestThread *test = new TestThread(this, lvModel); test->go(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtWidgets> #include "testthread.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); }; #endif // MAINWINDOW_H
testthread.cpp
#include "testthread.h" #include <QDebug> TestThread::TestThread(QObject *parent, QStandardItemModel *lvModel) : QThread(parent) { this->lvModel = lvModel; } void TestThread::go() { start(HighestPriority); } void TestThread::run() { for (int row = 0; row < lvModel->rowCount(); ++row) { QModelIndex idx = lvModel->index(row, 0, QModelIndex()); QStandardItem *item = new QStandardItem; item = lvModel->itemFromIndex(idx); QString name = item->data(Qt::DisplayRole).toString(); // next line triggers message for row = 0 only item->setData(name, Qt::ToolTipRole); qDebug() << row << item->data(Qt::DisplayRole); } }
testthread.h
#ifndef TESTTHREAD_H #define TESTTHREAD_H #include <QObject> #include <QtWidgets> class TestThread : public QThread { Q_OBJECT public: TestThread(QObject *parent, QStandardItemModel *lvModel); void go(); private: QStandardItemModel *lvModel; protected: void run() Q_DECL_OVERRIDE; }; #endif // TESTTHREAD_H
Application output:
Starting /Users/roryhill/Projects/build-testItem-Desktop_Qt_5_9_0_clang_64bit-Debug/testItem.app/Contents/MacOS/testItem...
QObject::connect: Cannot queue arguments of type 'QVector<int>'
(Make sure 'QVector<int>' is registered using qRegisterMetaType().)
0 QVariant(int, 0)
1 QVariant(int, 1)
2 QVariant(int, 2)My code seems to run okay, but after living with this for a few months I would like to know what I am doing wrong. Any help is much appreciated.
Rory
-
The message means that QObject::connect() and related functionality doesn't know how to copy the signal argument for delivery to a slot in a different thread. Registering the type, as hinted at by the message, will remove the warning. It can also be removed by changing the model's thread affinity via QObject::moveToThread(QThread *).
The warning likely refers indirectly to a real problem. I don't believe that the item views and models are thread safe. Both should be accessed from the same thread, which is generally the UI thread.
-
Thanks Jeremy
I don't know which type to register. I do not have any signal/slots in the code I've posted. Would this be one of Qt's built in slots?
You're probably right about it being something else. In the real code I do the setData inside a mutex.lock().
-
Okay, the solution is so simple it eluded me :*) All I had to do is take the warning literally.
qRegisterMetaType<QVector<int> >("QVector");
-
That will remove the message, but going back to the thread safety issue, the code is likely harboring a deeper issue.
Using a mutex in setData() will only prevent other threads from setting the value of an item at the same time. It won't handle other unsynchronized access such as reading data. Fixing that means examining the places where models and views interact.
For a counter example, look at the QML ListModel and WorkerScript example in http://doc.qt.io/qt-5/qtquick-threading-example.html. ListModel has explicit support for applying queued changes to the model via sync().
-
@jeremy_k
I'll check out the example. I'm tied up for a couple of days. Thanks very much for the help!