2
votes

I have a ListModel which stores a string "cityName" and a real value "TimeZoneOffset". As the name suggests, cityName holds the name of the city and TimeZoneOffset holds the time offset (from UTC) in minutes.

ListModel {
  id: worldCity

  ListElement {
   cityName: "London"
   TimeZoneOffset: 0
  }

  ListElement {
   cityName: "Amsterdam"
   TimeZoneOffset: 120
  }
}

This model is then used in a ListView. The ListView has a structure as shown in the code sample below.

ListView {
  model: worldCity
  currentIndex: -1

  delegate: ListItem.Standard {
    text: cityName        
    Label {
      text: timeOffSet + currentSystemTime
    }
  }
}

As you can see, my ListView is showing a modified output instead of directly outputting the listModel element. I need to update the ListView elements every minute to show the current time at a city. I plan on using a Timer to update it every minute.

How do I update every listView element?

3

3 Answers

7
votes

To me, updating the model directely doesn't seems the right option, here is an simplified and enhanced version of your code that does the thing right :

import QtQuick 2.0

Rectangle {
    width: 200;
    height: 400;

    property real currentTimestamp;

    function updateTime () {
        var now = new Date ();
        currentTimestamp = now.getTime ();
    }

    Timer {
        interval: 60000;
        repeat: true;
        running: true;
        onTriggered: { updateTime (); }
    }
    ListView {
        anchors.fill: parent;
        model: ListModel {
            ListElement { cityName: "London";     timeOffSet: 0;   }
            ListElement { cityName: "Amsterdam";  timeOffSet: 120; }
            ListElement { cityName: "Paris";      timeOffSet: 60;  }
        }
        delegate: Column {
            anchors {
                left: parent.left;
                right: parent.right;
            }

            Text {
                text: model.cityName;
                font.bold: true;
            }
            Text {
                text: Qt.formatTime (new Date (currentTimestamp + (model.timeOffSet * 60000)), "hh:mm A");
            }
        }
    }
    Component.onCompleted: { updateTime (); }
}
0
votes

The QML ListModel is very undocumented for scripting, but looking at its sourcecode, it's possible to know which methods are available to iterate with.

If you're using some JSON api and need the objects to be updated inline for example, or if you can't access the ListElement direcly, these are some methods that you can access from your model by scripting:

Q_INVOKABLE void clear();
Q_INVOKABLE void remove(int index);
Q_INVOKABLE void append(const QScriptValue&);
Q_INVOKABLE void insert(int index, const QScriptValue&);
Q_INVOKABLE QScriptValue get(int index) const;
Q_INVOKABLE void set(int index, const QScriptValue&);
Q_INVOKABLE void setProperty(int index, const QString& property, const QVariant& value);
Q_INVOKABLE void move(int from, int to, int count);
Q_INVOKABLE void sync();
0
votes

I prefer to keep the model on C++, Qt side. So it is posible to use all the proxymodel stuff. On Qt you have to set the C++ object m_pMyModel as properties to the QML world:

m_pQuickView->rootContext()->setContextProperty("_myModel", m_pMyModel);

and use it straight forward in QML:

    ListView {
            id: listView
            model : _myModel
            delegate : myDelegate
            ....
   }

To be able to use the data in QML delegates you have to create a roleNames hash:

 QHash<int, QByteArray> MyModel::roleNames() const
  {
    QHash<int, QByteArray> roles;
    roles[NameRole] = "name_role";
    roles[IconRole] = "icon_role";
    roles[StateRole] = "state_role";
    roles[TypeRole] = "type_role";
    return roles;
}