Qt Unable to move target to thread
<p>I'm facing a strange bug in my Qt 5.7 (on Windows 10) application and the usual culprits for this kind of behaviour are nowhere to be found:</p>

<ul>
<li>Object that is moved has a parent - most certainly not the case</li>
<li>Attempting to pull object to thread instead of pushing it - this is the reason for the error however I have no idea where it's coming from</li>
</ul>

<p>The full error message is</p>

<blockquote>
  <p>QObject::moveToThread: Current thread (0x2afcca68) is not the object's
  thread (0x34f4acc8). Cannot move to target thread (0x34f4adc8)</p>
  
  <p>QObject::setParent: Cannot set parent, new parent is in a different
  thread</p>
</blockquote>

<p>and here is also my code:</p>

<p><strong>main.cpp</strong></p>

<pre><code>#include &lt;QApplication&gt;
#include &lt;QQuickItem&gt;
#include "CustomQuickWidget.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);

    const QUrl source = QUrl(QLatin1String("qrc:/main"));
    CustomQuickWidget widget(source);

    return app.exec();
}
</code></pre>

<p><strong>main</strong> (alias for <strong>main.qml</strong>):</p>

<pre><code>// You can put any random QML content in this case really as long as it doesn't create a window since the CustomQuickWidget does that.
Rectangle {
    id: window
    visible: true
    width: 600
    height: 480
}
</code></pre>

<p><strong>CustomQuickWidget.cpp</strong></p>

<pre><code>#include "CustomQuickWidget.h"
#include &lt;QQuickItem&gt;

CustomQuickWidget::CustomQuickWidget(const QUrl &amp;source, QWidget *parent) : QQuickWidget(source, parent) {
    // Setup the recognizer
    this-&gt;airWheelRecognizer = new QAirWheelGestureRecognizer();
    this-&gt;airWheelType = QGestureRecognizer::registerRecognizer(airWheelRecognizer);
    // and turn on grabbing for all the supported gestures
    grabGesture(airWheelType);
    grabGesture(Qt::SwipeGesture);
    grabGesture(Qt::TapGesture);

    // Create thread and device worker
    this-&gt;deviceThread = new QThread(this);
    this-&gt;deviceWorker = new DeviceMapper(this, Q_NULLPTR); // NOTE: this here is NOT for parent. The constructor's signature for this class is: DeviceMapper(QObject* receiver, QList&lt;Qt::GestureType&gt;* gestureIDs, QObject* parent = Q_NULLPTR)
    this-&gt;deviceWorker-&gt;init();

    // Create timer that will trigger the data retrieval slot upon timeout
    this-&gt;timer = new QTimer();
    this-&gt;timer-&gt;setTimerType(Qt::PreciseTimer);
    this-&gt;timer-&gt;setInterval(5);

    // Move timer and device mapper to other thread
    this-&gt;timer-&gt;moveToThread(this-&gt;deviceThread);
    this-&gt;deviceWorker-&gt;moveToThread(this-&gt;deviceThread); // FIXME For unknown reason: QObject::moveToThread: Current thread (...) is not the object's thread. Cannot move to target thread

    // Connect widget, timer and device mapper
    createConnections();

    // Run thread
    this-&gt;deviceThread-&gt;start();

    // Connect device and start data retrieval
    QTimer::singleShot(0, this-&gt;deviceWorker, &amp;(this-&gt;deviceWorker-&gt;slotToggleConnection));
    QTimer::singleShot(0, this-&gt;deviceWorker, &amp;(this-&gt;deviceWorker-&gt;slotToggleRun));

    this-&gt;show();
}

CustomQuickWidget::~CustomQuickWidget()
{
    if (this-&gt;deviceThread) {
        this-&gt;deviceThread-&gt;quit();
        this-&gt;deviceThread-&gt;wait();
    }
}

void CustomQuickWidget::createConnections()
{
    connect(this-&gt;timer, SIGNAL(timeout()),
            this-&gt;deviceWorker, SLOT(slotRetrieveData()));

    connect(this-&gt;deviceThread, SIGNAL(started()),
            this-&gt;timer, SLOT(start()));
    connect(this-&gt;deviceThread, SIGNAL(finished()),
            this-&gt;deviceWorker, SLOT(deleteLater()));
    connect(this-&gt;deviceThread, SIGNAL(finished()),
            this-&gt;deviceThread, SLOT(deleteLater()));
}

bool CustomQuickWidget::event(QEvent* event) {
    if (event-&gt;type() == QEvent::Gesture) { 
        bool res = gestureEvent(static_cast&lt;QGestureEvent*&gt;(event)); // Not important so not included as code here
        return res;
    }

    return QWidget::event(event);
}
</code></pre>

<p>As you can see I have a typical worker-thread-thing going on here. I've made sure that my worker (here <code>DeviceMapper</code>) doesn't have a parent. It is also instantiated inside my widget (where the <code>QThread</code> is also created) but moved to the thread along with a timer.</p>

<p>Now beside the obvious issue here that is in the title I have to mention the following:</p>

<ul>
<li>There is no such error when <code>this-&gt;timer-&gt;moveToThread(this-&gt;deviceThread);</code> is called</li>
<li>This very same code works without any issue in another project, which is a subdirs project - one sub-project creates the shared library (which I'm using in this project too) and the other - an application that uses the library.</li>
</ul>

<p>The only difference between my other application and this one is the usage of <code>QQuickWidget</code> (instead of <code>QWidget</code>) and <code>QML</code>. I'm quite new to <code>QML</code> and this is also my first <code>QQuickWidget</code> so I might be missing some obvious setting that needs to be "activated".</p>

<p>I've also added</p>

<pre><code>cout &lt;&lt; this-&gt;deviceWorker-&gt;thread()-&gt;currentThreadId() &lt;&lt; endl;
cout &lt;&lt; this-&gt;thread()-&gt;currentThreadId() &lt;&lt; endl;
</code></pre>

<p>right before <code>this-&gt;deviceWorker-&gt;moveToThread(this-&gt;deviceThread);</code> and I got</p>

<pre><code>0x18b0
0x18b0
</code></pre>

<p>which means that before the <code>moveToThread(...)</code> my object belongs to the same thread where the <code>QThread</code> is instantiated. Printing the thread ID after the <code>moveToThread(...)</code> returns the same result but this is expected due to the failure to properly move the object to the other thread.</p>

<hr>

<p><strong>UPDATE:</strong></p>

<p>The error message appears ONLY when building in release mode however no matter the type of build I have the bug is still present.</p>