Qt 5.7 (Windows 10) アプリケーションで奇妙なバグに直面していますが、この種の動作の通常の犯人はどこにも見つかりません。
- 移動されるオブジェクトには親があります - ほとんどの場合そうではありません
- オブジェクトをプッシュする代わりにスレッドにプルしようとしています - これがエラーの原因ですが、どこから来ているのかわかりません
完全なエラー メッセージは次のとおりです。
QObject::moveToThread: 現在のスレッド (0x2afcca68) はオブジェクトのスレッド (0x34f4acc8) ではありません。ターゲット スレッドに移動できません (0x34f4adc8)
QObject::setParent: 親を設定できません。新しい親は別のスレッドにあります
ここにも私のコードがあります:
main.cpp
#include <QApplication>
#include <QQuickItem>
#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();
}
main ( main.qmlのエイリアス):
// 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
}
CustomQuickWidget.cpp
#include "CustomQuickWidget.h"
#include <QQuickItem>
CustomQuickWidget::CustomQuickWidget(const QUrl &source, QWidget *parent) : QQuickWidget(source, parent) {
// Setup the recognizer
this->airWheelRecognizer = new QAirWheelGestureRecognizer();
this->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->deviceThread = new QThread(this);
this->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<Qt::GestureType>* gestureIDs, QObject* parent = Q_NULLPTR)
this->deviceWorker->init();
// Create timer that will trigger the data retrieval slot upon timeout
this->timer = new QTimer();
this->timer->setTimerType(Qt::PreciseTimer);
this->timer->setInterval(5);
// Move timer and device mapper to other thread
this->timer->moveToThread(this->deviceThread);
this->deviceWorker->moveToThread(this->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->deviceThread->start();
// Connect device and start data retrieval
QTimer::singleShot(0, this->deviceWorker, &(this->deviceWorker->slotToggleConnection));
QTimer::singleShot(0, this->deviceWorker, &(this->deviceWorker->slotToggleRun));
this->show();
}
CustomQuickWidget::~CustomQuickWidget()
{
if (this->deviceThread) {
this->deviceThread->quit();
this->deviceThread->wait();
}
}
void CustomQuickWidget::createConnections()
{
connect(this->timer, SIGNAL(timeout()),
this->deviceWorker, SLOT(slotRetrieveData()));
connect(this->deviceThread, SIGNAL(started()),
this->timer, SLOT(start()));
connect(this->deviceThread, SIGNAL(finished()),
this->deviceWorker, SLOT(deleteLater()));
connect(this->deviceThread, SIGNAL(finished()),
this->deviceThread, SLOT(deleteLater()));
}
bool CustomQuickWidget::event(QEvent* event) {
if (event->type() == QEvent::Gesture) {
bool res = gestureEvent(static_cast<QGestureEvent*>(event)); // Not important so not included as code here
return res;
}
return QWidget::event(event);
}
ご覧のとおり、ここでは典型的なワーカー スレッドの処理が行われています。ワーカー (ここでDeviceMapper
は ) に親がないことを確認しました。ウィジェット内でもインスタンス化されますが(QThread
も作成されます)、タイマーとともにスレッドに移動されます。
ここで、タイトルにある明らかな問題に加えて、次のことを言及する必要があります。
this->timer->moveToThread(this->deviceThread);
が呼び出されたときにそのようなエラーはありません- このまったく同じコードは、サブディレクトリ プロジェクトである別のプロジェクトでも問題なく動作します。1 つのサブプロジェクトは共有ライブラリ (このプロジェクトでも使用しています) を作成し、もう 1 つのサブプロジェクトはライブラリを使用するアプリケーションを作成します。
私の他のアプリケーションとこのアプリケーションの唯一の違いは、QQuickWidget
(の代わりにQWidget
) とを使用することQML
です。私はまったく初めてでQML
、これも初めてQQuickWidget
なので、「アクティブ化」する必要がある明らかな設定が欠落している可能性があります。
私も追加しました
cout << this->deviceWorker->thread()->currentThreadId() << endl;
cout << this->thread()->currentThreadId() << endl;
直前にthis->deviceWorker->moveToThread(this->deviceThread);
、私は得ました
0x18b0
0x18b0
これは、 my オブジェクトがインスタンス化さmoveToThread(...)
れたスレッドと同じスレッドに属する前であることを意味します。QThread
の後にスレッド ID を出力してmoveToThread(...)
も同じ結果が返されますが、これはオブジェクトを他のスレッドに適切に移動できなかったために予想されるものです。
アップデート:
エラー メッセージは、リリース モードでビルドする場合にのみ表示されますが、ビルドの種類に関係なく、バグは依然として存在します。