Search code examples
qtcalendarqmlqt5qtquickcontrols

QML Calendar: list of visible days


Is there a way to get a list of visible days for the current month view (including the ones from previous/next month that are also visible)


Solution

  • If we inspect the code of the Calendar here we can find a suspicious property __model. We find, it has always a count of 42 - which is the amount of days that are visible.

    The problem is, that in QML we can't really access descendants of QAbstractItemModels, as we need a QModelIndex to fetch data, struggle with int instead of roleNames to identify the roles e.t.c.
    So we need to introduce a little helper, that offers a get(index) function to us, as known from the ListModel. As base for this, we can use the QIdentityProxyModel that we'll extend by the missing, exposed method.

    qmlproxymodel.h

    #ifndef QMLPROXYMODEL_H
    #define QMLPROXYMODEL_H
    
    #include <QObject>
    #include <QIdentityProxyModel>
    #include <QMap>
    
    class QMLProxyModel : public QIdentityProxyModel
    {
        Q_OBJECT
    public:
        QMLProxyModel(QObject* parent = nullptr);
    
    public slots:
        QMap<QString, QVariant> get(int row_index) const;
    };
    
    #endif // QMLPROXYMODEL_H
    

    qmlproxymodel.cpp

    #include "qmlproxymodel.h"
    
    QMLProxyModel::QMLProxyModel(QObject* parent)
        : QIdentityProxyModel(parent)
    {
    
    }
    
    QMap<QString, QVariant> QMLProxyModel::get(int row_index) const
    {
        QMap<QString, QVariant> ret;
        QModelIndex ind = index(row_index, 0);
        QHash<int, QByteArray> roles = roleNames();
    
        // for some reason the itemData-method always throw a index-out-of-range exception
        for (int e : roles.keys()) {
            ret.insert(roles.value(e), data(ind, e));
        }
    
        return ret;
    }
    

    Then we register this new type to QML in our main.cpp

    qmlRegisterType<QMLProxyModel>("QMLProxyModel", 1, 0, "QMLProxyModel");
    

    Finally we use it in QML:

    Calendar {
        id: cal
        anchors.fill: parent
    }
    
    QMLProxyModel {
        id: pm
        sourceModel: cal.__model
        onDataChanged: console.log("Some Data has changed", pm.get(0).date)
    }
    

    Here I output the date of the first displayed date whenever the data of the model changes - that is, when the next month is selected.
    It should be easy for you, to write a JS function to iterate over all (42) elements of the QMLProxyModel to add the content to any data structure, you desire.