Congratulations to our 2022 Qt Champions!

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"));;

    // 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..

  • Can you provide an example?

  • 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..");
    } 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_PROPERTY (bool connected READ isConnected WRITE setConnected NOTIFY connectedChanged);

    QmlCppMediator(QObject* parent) :
    m_connected(false) {}

    void setConnected(bool value) {m_connected = value; emit connectedChanged();}
    bool isConnected() {return m_connected;}


    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": 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;
    QmlCppMediator m_qmlCppMediator;
    QDeclarativeContext *context = viewer.rootContext();
    context->setContextProperty("cppInterface", &m_qmlCppMediator);
    IcecastServer icecastServer(&m_qmlCppMediator);
    return app.exec(&#41;;


  • Hi,

    You should be able to get rid of the error by setting the context property before calling setMainQmlFile().


  • Indeed: first setup the context with the mediator object, and then set the QML.

Log in to reply