QtQuick.XmlListModel 2.0 でアイテムが追加された場合の処理を書く

ちょっと古いネタですが、この間会った時 に同じことを言っていた気がしたのでブログに書いておく。

QtQuick 1.0 の XmlListModel の実装は QDeclarativeXmlListModel というクラスで行われており、モデルとしてのインターフェースは基底クラスの QListModelInterface になります。このクラスは void itemsInserted(int index, int count); というシグナルを持っており、XmlListModel のデータが増えた際にこのシグナルが発生するため、(ドキュメントに載っていないため公式な API ではありませんが) onItemInserted: というハンドラで処理を行うことができました。

QtQuick 2.0 では、XmlListModel の再実装が行われ、QQuickXmlListModel というクラスに変わりました。アイテムの追加や削除は基底クラスの QAbstractListModel のさらに基底クラスの QAbstractItemModel がインターフェースになります。

というわけで、QtQuick 2.0 の XmlListModel の要素の追加時には void rowsInserted(const QModelIndex & parent, int start, int end) シグナルが発生するため、QML でハンドラを書く場合には onRowsInserted: の中で start と end を見て処理をするようになります。

確認に使ったソース

import QtQuick 2.0
import QtQuick.XmlListModel 2.0

GridView {
    width: 360
    height: 360
    cellWidth: width / 3
    cellHeight: height / 3

    model: XmlListModel {
        id: model
        source: 'http://feeds.feedburner.com/TEDTalks_video'
        query: '/rss/channel/item'
        namespaceDeclarations:
            "declare namespace media=\"http://search.yahoo.com/mrss/\";"

        XmlRole { query: 'title/string()'; name: 'title' }
        XmlRole { query: 'description/string()'; name: 'description' }
        XmlRole { query: 'media:thumbnail/@url/string()'; name: 'icon'}
        XmlRole { query: 'media:content/@url/string()'; name: 'content'}

        onRowsInserted: {
            console.debug('Inserted from: %1; to: %2'.arg(first).arg(last))
        }
    }

    delegate: Image {
        width: GridView.view.width / 3
        height: GridView.view.height / 3
        source: model.icon
        fillMode: Image.PreserveAspectCrop
        clip: true

        Rectangle {
            visible: parent.status === Image.Ready
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            height: parent.height / 3
            gradient: Gradient {
                GradientStop { position: 1.0; color: '#000000' }
                GradientStop { position: 0.0; color: 'transparent' }
            }
            Text {
                anchors.fill: parent
                verticalAlignment: Text.AlignBottom
                color: 'white'
                text: model.title
            }
        }
    }
}