суббота, 11 февраля 2012 г.

Создание своей модели данных на основе QAbstractListModel

Создание своей модели данных на основе QAbstractListModel
(релиз Qt SDK на момент написания данной статьи - 1.2.0)

Предположим что вам необходимо разработать какую-то программу, которая в большинстве своём выводит списочные данные. Это может быть список загрузок, телефонная книга, аська и т. д.
В этой статье я вам расскажу как разработать свою модель данных, которую в другой статье мы сможем портировать в QML.


Будем мы разрабатывать телефонную книгу, в которой из контактов у нас есть имя, телефон и возраст. Ради большего интереса мы будем выводить возраст не числом, а возрастной шкалой (от 0 до 100 лет).
В соответствии с вступлением к книге Страуструпа по С++, представим наш контакт в виде класса:

class Contact
{
public:
    Contact(QString _name, QString _phone, uint _age)
    {
        name = _name;
        phone = _phone;
        age = _age;
    }
    void setName (QString _name)
    {
        name = _name;
    }
    void setPhone (QString _phone)
    {
        phone = _phone;
    }
    void setAge (uint _age)
    {
        age = _age;
    }
    QString getName() const
    {
        return name;
    }
    QString getPhone() const
    {
        return phone;
    }
    uint getAge() const
    {
        return age;
    }
private:
    QString name;
    QString phone;
    uint age;
};

т. е. в нашем классе у каждого контакта есть имя, телефон и возраст. Я не буду усложнять себе жизнь проверкой значений, а вы, если хотите, можете конечно же похимичить.
Следующим шагом мы создаём нашу модель на базе QAbstractListModel для которой определим конструктор и функцию добавления контактов в модель. Кроме того нам необходимо определить множество возможных полей модели. Для наглядности я их прокомментирую в коде дополнительно. Заголовочный файл нашей модели выглядит следующим образом:
#ifndef PHONEMODEL_H
#define PHONEMODEL_H
#include <QAbstractListModel>
#include <QList>
#include <QVariant>
#include <QModelIndex>
#include "contact.h"
class PhoneModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit PhoneModel(QObject *parent = 0);
enum contactRolse { // множество возможных значений поля 
        NameRole = Qt::DisplayRole, // заголовок для элемента модели ( для нас это имя контакта)
        PhoneRole = Qt::UserRole + 1,  // номер телефона
        AgeRole = Qt::UserRole + 2  // возраст
    };
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; // функция доступа к данным
    int rowCount(const QModelIndex &parent) const; // количество элементов в модели 
public slots:
    void addContact(Contact ct); // добавить контакт в модель
private:
    QList<Contact> contacts; // список контактов
    QHash<int, QByteArray> roles; // роли
};
#endif // PHONEMODEL_H

Определение этих методов выглядит следующим образом:

PhoneModel::PhoneModel(QObject *parent) :
    QAbstractListModel(parent)
{
    roles[NameRole] = "name";
    roles[PhoneRole] = "phone";
    roles[AgeRole] = "age";
    setRoleNames(roles);
}
В данном консрукторе мы задаём значения полей для каждой роли.

Далее:

QVariant PhoneModel::data(const QModelIndex &index, int role) const
{
    if (index.row() < 0 || index.row() > contacts.count())
        return QVariant();
    const Contact & ct = contacts[index.row()];
        if (role == NameRole)
            return ct.getName();
        else if (role == PhoneRole)
            return ct.getPhone();
        else if (role == AgeRole)
            return ct.getAge();
        return QVariant();
}
В данной функции мы возращаем значение выбранного поля по его имени, если такого имени поля нет, возвращаем пустой QVariant.

Функция добавления контакта - всё просто :) :

void PhoneModel::addContact(Contact ct)
{
    contacts << ct;
}

Функция возвращения количество строк данных в модели возвращает количество элементов списка:
int PhoneModel::rowCount(const QModelIndex &parent) const
{
    return contacts.size();
}

Модель мы создали, осталось дело за малым: портировать её в QML и красивенько отобразить. Но об этом уже в следующей статье...




2 комментария:

  1. В конце конструктора у Вас вызывается метод setRoleNames(roles);
    Что это за метод и из какого он класса?

    ОтветитьУдалить
  2. Может позновато... В общем это метод в библиотеке версии 4.8.х, он задавал различные роли для производного классаю В 5.1, если не ошибаюсь, надо переопределить метод roleNames или что-то в этом духе.

    ОтветитьУдалить