1
votes

I'm creating a game and currently I've encountered a problem with QML. I need to make my C++ thread wait for user to make a decision which will be received by some QML component (for example MouseArea). To demonstrate the problem better, I've written some simple code that represents what I'm trying to do:

//main.cpp
#include <QApplication>
#include "someclass.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    SomeClass c;

    return a.exec();
}

//someclass.h
#ifndef SOMECLASS_H
#define SOMECLASS_H

#include <QQuickView>
#include <QQuickItem>
#include <QObject>

class SomeClass : public QObject
{
    Q_OBJECT
public:
    SomeClass();

    void lock();

public slots:
    void unlock();

private:
    QQuickView view;
    bool unlockSignalReceived;
};

#endif // SOMECLASS_H

//someclass.cpp
#include "someclass.h"

SomeClass::SomeClass()
{
    view.setSource(QUrl("qrc:/QMLFile.qml"));
    view.setGeometry(0,0,1000,1000);
    view.show();
    unlockSignalReceived=1;
    QObject::connect(view.rootObject(), SIGNAL(click()),this, SLOT(unlock()));
    lock();
    QMetaObject::invokeMethod(view.rootObject(), "changeColor", Q_ARG(QVariant, "green"));
}

void SomeClass::lock()
{
    unlockSignalReceived=0;
    while (!unlockSignalReceived);
}

void SomeClass::unlock()
{
    unlockSignalReceived=1;
}

//qmlfile.qml
import QtQuick 2.5

Item {
    id: root

    anchors.fill: parent

    function changeColor(color)
    {
        rec.color = color;
    }

    signal click()

    Rectangle{
        id: rec

        anchors.fill: parent

        color: "red"
    }
    MouseArea{
        id: mArea

        anchors.fill: parent

        onClicked: click()
    }
}

I think that it should show a red rectangle that, when the user clicks it, changes its color to green. If I remember correctly Qt GUI is run in different thread than C++ logic thread, so I guess that it should be able to execute unlock() slot during lock() execution. But if it doesn't work, then probably I'm totally wrong. What is even more interesting, the rectangle doesn't even show, albeit view.setSource(QUrl) is invoked before lock(). Could someone explain, why it doesn't work and how to deal with this problem?

1

1 Answers

2
votes

You are in a single threaded application and your thread executes a loop that never ends.

Instead of trying to loop just remember that you are in an event driven system. Just react to the signal.

Btw, it is a lot better to avoid creating dependencies for C++ on QML code, so instead of retrieving the root object, connecting to its signal and calling its function, expose the C++ object and let the QML code call the C++ logic. See QQmlContext::setContextProperty(QString, QObject*)