Change QML-property in C++
-
I've got a ToolButton (QML Desktop Widgets) and want to change its icon.
@ ToolButton{
objectName: "imgConnected"
iconSource: "images/not-connected.png"
anchors.verticalCenter: parent.verticalCenter
}@Now when I try to change the iconSource I do this:
@
QDeclarativeView view(QUrl("qml/MyProject/main.qml"));
view.show();// get root object QObject *rootObject = dynamic_cast<QObject *>(view.rootObject()); // find element by name QObject *image = rootObject->findChild<QObject *>(QString("imgConnected")); image->setProperty("iconSource", QString("D:/Dropbox/Projekte/MyProject/release/images/connected.png"));
@
(I know that I have to remove the absolute path, its just there for testing).
My problem is that whenever this code is executed another window looking like the Mainwindow pops up for a second and then hides. The iconSource never changes visibly though.
-
What you can do is assign a variable for that icon and change that variable from C++ side so
that icon updates.. I was using that technique for states and it was working well.. -
Say you have a onStateChange slot somewhere in you QDV implementation and you want to change state property of you QML ui. You could write the slot like that
@
void SignageView::onStateChange(const QString &newState)
{
QDeclarativeProperty state(rootObject(), QString("state"));if (state.type() == QDeclarativeProperty::Invalid) { WRT("state propery is invalid, unable to change qml state.."); return; } else { state.write(newState); // should reflect immediately }
}
@AFAIK as long as you provide the notify() calls of your QProperty's you can use those properties in QML too.
-
I think that you should try to solve this by having the C++ side "announcing" when is has changed to connected state.
One way could be to set a context property:
@
view->rootContext()->setContextProperty("connected", mgr->isConnected());
@
You have to set this property each time the connection changes.The QML file could look something like this:
@
ToolButton {
...
iconSource: connected ? "images/connected.png" : "images/disconnected.png"
}
@By doing this, the view controls what image should be shown when, not the C++ side.
-
First of all: I think your (Hedge) approach should work. If it does not, then that is worth digging in to further.
On the other hand, I think that this approach is not the most elegant, and if possible, should be avoided. Instead, you can insert a QObject in your QML environment and use the property binding methods. For that to work, you need to create a QObject class like this:
@
class QmlCppMediator: public QObject {
Q_OBJECTQ_PROPERTY (bool connected READ isConnected WRITE setConnected NOTIFY connectedChanged);
public:
QmlCppMediator(QObject* parent) :
QObject(parent),
m_connected(false) {}void setConnected(bool value) {m_connected = value; emit connectedChanged();} bool isConnected() {return m_connected;}
signals:
connectedChanged();private:
bool m_connected;
}@Of course, your bridge could have many more methods to interface between your QML and your C++ parts, and the properties could also be implemented in other ways. The idea is that you provide a "mediator":http://en.wikipedia.org/wiki/Mediator_pattern between your C++ and your QML.
You can insert an instance (probably the instance) of this class using the setContextProperty method mentioned by mario above:
@
view->rootContext()->setContextProperty("cppInterface", m_qmlCppMediator);
@You can then connect to the exposed properties like this:
@
ToolButton {
...
iconSource: cppInterface.connected ? "images/connected.png" : "images/disconnected.png"
}
@
You can of course group functionality that logically belongs together in such a mediator object, and use more than one of these. -
Thanks for all your help. I implemented it as Andre said.
It finally works.
One error keeps bugging me though.
I've got bq. file:///D:/MyProject/main.qml:28: ReferenceError: Can't find variable: cppInterface
For some reasons it still works.That is how my main-function looks like:
@int main(int argc, char *argv[])
{
QApplication app(argc, argv);QmlApplicationViewer viewer; viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto); viewer.setMainQmlFile(QLatin1String("main.qml")); viewer.showExpanded(); QmlCppMediator m_qmlCppMediator; QDeclarativeContext *context = viewer.rootContext(); context->setContextProperty("cppInterface", &m_qmlCppMediator); m_qmlCppMediator.setConnected(true); IcecastServer icecastServer(&m_qmlCppMediator); return app.exec();
}@