PDA

View Full Version : Connecting QML to a C++ signal - connection doesn't work on the first time



frankiefrank
22nd September 2011, 15:01
I'm playing around with connections between C++ and QML.

I've found a case in which it seems like a signal connection doesn't work at first, then works on calls from other locations in the code.

A bit of code to clarify:



// Header
#include <QObject>
#include <QDateTime>

class MyQmlInterface : public QObject
{
Q_OBJECT

public:

Q_PROPERTY(QString singleValue READ singleValue WRITE setSingleValue NOTIFY singleValueChanged)

const QString &singleValue() const;
void setSingleValue(const QString &newSingleValue);
void emitCppSignal(const QString &passedStr);

Q_INVOKABLE QDateTime getCurrentDateTime() const {
return QDateTime::currentDateTime();
}

signals:
void singleValueChanged();
// THIS is the signal I want to connect to
void signalFromCpp(const QString &passedStr);

public slots:
void somethingHappened();

private:
QString mSingleValue;
};

// Cpp

const QString &MyQmlInterface::singleValue() const
{
return mSingleValue;
}

void MyQmlInterface::setSingleValue(const QString &newSingleValue)
{
if (newSingleValue == mSingleValue)
return;
mSingleValue = newSingleValue;
emit singleValueChanged();
}

void MyQmlInterface::somethingHappened()
{
setSingleValue("O RLY");
}

// Method to emit the signal
void MyQmlInterface::emitCppSignal(const QString &passedStr)
{
emit signalFromCpp(passedStr);
}

// QML

import QtQuick 1.0

Rectangle {
width: 360
height: 360

Text {
id: myText
anchors.centerIn: parent
text: myInterface.singleValue
}

Connections {
target: myInterface
onSignalFromCpp: {
myText.text += passedStr
myText.rotation += 90
}
}
}



Now here is where I initialize my Qml display and expect to see the result of my signal being emitted:


// The types are what you expect :)
mView = new QDeclarativeView(this);
mEngine = mView->engine();
mContext = mEngine->rootContext();

mQmlInterface = new MyQmlInterface;

QString filePath = "D:\\QmlTest\\QmlTest.qml";
mView->setSource(filePath);

mContext->setContextProperty("myInterface", mQmlInterface);
mQmlInterface->setSingleValue("Set after context...");

ui.verticalLayout->addWidget(mView);
mView->show();

//! If needed - this is how to clean up in case Qml wants to quit
//connect(mEngine, SIGNAL(quit()), this, SLOT(declarativeEngineQuit()));

// This first signal call doesn't work
mQmlInterface->emitCppSignal("this getting to you?");


The above code runs when I click on a button to "start" the qml test. In a different place in my code (index change of a table widget) I call the same method.


mQmlInterface->emitCppSignal("this getting to you?");


Current behavior is that only the index change calls are getting through the QML. For my implementation I can live with that but why is it happening? Is this a bug?

A.J.Rimmer
16th October 2011, 03:19
You have to register your class to qdeclarative engine to be able to connect to C++ object signals which are not notify signals of object properties. Registration can be done using qmlRegisterType template function:


template<typename T>
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName)

For you code it would be for example:


qmlRegisterType<MyQmlInterface>("MyQmlInterfaceNamespace", 1, 0, "MyQmlInterface");

More info:
http://doc.qt.nokia.com/4.7/qdeclarativeengine.html#qmlRegisterType
http://doc.qt.nokia.com/4.7/qml-extending.html

frankiefrank
16th October 2011, 08:53
Thanks for your reply.

The code given here should still work. And as matter of fact, it does, for any later call to emitCppSignal. That's why I wrote, it doesn't work only for the first call.
I changed some things in my actual project so I don't have this first call in my working code, but if I manage to find time to repeat it I'll try to post a better explanation of the issue.