Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Много вопросов про модель\представление
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Модель/Представление
Xantrax
Здравствуйте, есть ряд вопросов по архитектуре модель\представление.
Читаю http://qtdocs.narod.ru/, раздел создание новых моделей...
Источник данных у нас QStringList, значит можно унаследоваться от QAbstractListModel, что и делается в объяснении...
Наследуюсь:
[B]mystringlistmodel.h[/B]
class MyStringListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit MyStringListModel(QStringList &strings, QObject *parent = 0);
    
private:
    QStringList stringList;
    
};
[B]mystringlistmodel.cpp[/B]
MyStringListModel::MyStringListModel(QStringList &strings,QObject *parent) :
    QAbstractListModel(parent)
{
    stringList<<strings;
}

Определяя конструктор сталкиваюсь с проблемой, что не могу инициализировать приватную переменную QStringList stringList
 stringList(strings);

no match for call to '(QStringList) (QStringList&)'
а вот таким образом могу:
 stringList<<strings;

Хорошо, далее....
Написано, что "Кроме конструктора модели, мы должны реализовать только две функции: rowCount(), data()". Зачем, если я могу ни разу эти функции не вызвать?
Далее они переопределяют виртуальный метод rowCount(), ну и я собственно у себя этот метод в классе епреопределяю:
  
int StringListModel::rowCount(const QModelIndex &parent) const
    {
        return stringList.count();
    }

Вот только зачем туда подавать QModelIndex &parent, если мы его нигде не спользуем?
Хорошо, допустим далее, я хочу посмотреть что у меня получилось, беру свою модель, беру представление (QListView) и отображаю все это на виджете...
   QStringList stringlist;
    stringlist << "One" << "Two" << "Three" << "Four" << "Five";
    MyStringListModel *mystringlistmodel = new MyStringListModel(stringlist,this);

    QListView *listview = new QListView(this);
    listview->setModel(mystringlistmodel);

Допустим я не зря переопределил виртуальный метод класса QAbstractListModel rowCount(const QModelIndex &parent), как теперь мне узнать количество строк в моей модели?
   qDebug() << mystringlistmodel->rowCount();[

Метод требует QModelIndex &parent, что туда подать?
QModelIndex parent = mystringlistmodel->index(0,0,QModelIndex());
?
Далее, нам в руководстве предлагается переопределить еще один виртуальный метод data();
 QVariant StringListModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid())
            return QVariant();

        if (index.row() >= stringList.size())
            return QVariant();

        if (role == Qt::DisplayRole)
            return stringList.at(index.row());
        else
            return QVariant();
    }

И тут у меня ступор, если index не валидный(первое if()), то что возвращается? Аналогично, что возвращается, если срабатывает второй if()? Рандомное число? А может лучше вернуть что-нить такое, чтобы понять что идекс не валидный, или индекс вернулся больше количества срок в stringList?
В общем, как-то все жутко на первых порах...

ilyabvt
Цитата

Читать документацию к версии 4.1, когда уже вышла 5.1, не совсем разумно. Неужели из-за того что оригинальная документация на английском?
Цитата
no match for call to '(QStringList) (QStringList&)'

Потому что у QStringList нет конструктора принимающего QStringList по ссылке, только по const ссылке. У себя в конструкторе используйте константную ссылку.
Цитата
Написано, что "Кроме конструктора модели, мы должны реализовать только две функции: rowCount(), data()". Зачем, если я могу ни разу эти функции не вызвать?

Базовый класс может.
Цитата
Далее они переопределяют виртуальный метод rowCount(), ну и я собственно у себя этот метод в классе епреопределяю:
 int StringListModel::rowCount(const QModelIndex &parent) const
    {
        return stringList.count();
    }

Вот только зачем туда подавать QModelIndex &parent, если мы его нигде не спользуем?

Это просто пример простейшего rowCount.
Цитата
Метод требует QModelIndex &parent, что туда подать?

Вот пример на 3 строки:
http://qt-project.org/doc/qt-5.1/qtwidgets...g-model-indexes
Цитата
И тут у меня ступор, если index не валидный(первое if()), то что возвращается? Аналогично, что возвращается, если срабатывает второй if()?

Возвращается заведомо некорректный QVariant.
Цитата
А может лучше вернуть что-нить такое, чтобы понять что идекс не валидный, или индекс вернулся больше количества срок в stringList?

Вы как раз и возвращаете ответ который дает понять что индекс не валидный.
Анна
Цитата(Xantrax @ 25.11.2013, 0:45) *
no match for call to '(QStringList) (QStringList&)'

Наверное, потому что в определениии конструктора написано так QStringList ( const QString & str ). -> const <- попробуй добавить в аргумент конструктора.
Цитата(Xantrax @ 25.11.2013, 0:45) *
Написано, что "Кроме конструктора модели, мы должны реализовать только две функции: rowCount(), data()". Зачем, если я могу ни разу эти функции не вызвать?
Ты, может, и не вызовешь их, зато сама модель ими пользуется, вьювер ими пользуется.
Цитата(Xantrax @ 25.11.2013, 0:45) *
Вот только зачем туда подавать QModelIndex &parent, если мы его нигде не спользуем?

Потому, что эта функция так определена в родительском классе:
int QAbstractItemModel::rowCount ( const QModelIndex & parent = QModelIndex() ) const [pure virtual]
Обрати внимание на [pure virtual] . Это тоже ответ на твой вопрос "Зачем, если я не буду вызывать?" и это означает, что ,если ты не переопределишь эту функцию, то твой класс останется виртуальным, и компелятор тебя обругает.

Цитата(Xantrax @ 25.11.2013, 0:45) *
Метод требует QModelIndex &parent, что туда подать?

Если ты внимательно посмотришь на определение rowCount, то увидишь, что за тебя уже всё сделали - const QModelIndex & parent = QModelIndex() - тебе и аргумент определили и по умолчанию в него подставили QModelIndex(),и тебе уже ничего не надо указывать в качестве аргумента.

Цитата(Xantrax @ 25.11.2013, 0:45) *
И тут у меня ступор, если index не валидный(первое if()), то что возвращается?

Возвращается пустышка. Вьювер знает, что делать с QVariant() - он тебе ничего не отобразит (ну, нечего отбражать!).

Цитата(Xantrax @ 25.11.2013, 0:45) *
Рандомное число? А может лучше вернуть что-нить такое, чтобы понять что идекс не валидный, или индекс вернулся больше количества срок в stringList?
В общем, как-то все жутко на первых порах...

Так ведь QVariant() и означает "ничего" - У меня нет ничего, что можно было бы отобразить для этого индекса (потому что он невалидный - например, он содержит координаты -1, -1 ), у меня нет ничего для индекса, который вылетел за пределы моего списка, я могу предложить тебе для данного индекса только то, что можно отобразить на экране (это третий if).
Не забывай, что всё завязано на QAbstractItemModel - классе, который сделан как можно более универсалей. Авторы не могут предугадать, что именно тебе захочестя видеть в качестве данных в твоём списке - строки, инты, ёлочные игрушки или другие подарки, поэтому тебе сделали универсальную коробочку и работают с коробоской, а уж что ты туда положишь, это уже твоя забота, а не их, хоть слона положи. В QVariant это универсальная обёртка для почти любых данных, туда можно положить, всё что угодно (до некоторой степени, конечно), И большинство классов умеют и будут работать с этой обёрткой. QVariant() означает "ничего" - У меня нет ничего, что можно было бы отобразить для этого индекса, у меня нет ничего для индекса, который вылетел за пределы моего списка, я могу предложить тебе для данного индекса только то, что можно отобразить на экране (это третий if).
В общем, почитай обзорные статьи в аасистенте про Модель/Представление, ты многое поймёшь.

ilyabvt, ;) !
Steklova Olga
Привет!
Цитата(Xantrax @ 25.11.2013, 0:45) *
no match for call to '(QStringList) (QStringList&)'
такая ошибка может возникнуть, если описав класс так
mystringlistmodel.h
class MyStringListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit MyStringListModel(QStringList &strings, QObject *parent = 0);
private:
    QStringList stringList;
};
пытаться сделать так
mystringlistmodel.cpp
MyStringListModel::MyStringListModel(QStringList &strings,QObject *parent) :
    QAbstractListModel(parent)
{
    stringList(strings); //? кто же так пишет, это пародия на конструктор QStringList
}
ты неверно списал пример!
надо так:
mystringlistmodel.h
#ifndef MYSTRINGLISTMODEL_H
#define MYSTRINGLISTMODEL_H

#include <QAbstractListModel>
#include <QtCore\QStringList>

class MyStringListModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit MyStringListModel(const QStringList &strings, QObject *parent = 0)
            : QAbstractListModel(parent), stringList(strings) {}

    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role) const;

private:
    QStringList stringList;
};

#endif // MYSTRINGLISTMODEL_H
mystringlistmodel.cpp
#include "mystringlistmodel.h"

int MyStringListModel::rowCount(const QModelIndex &parent) const
{
    return stringList.count();
}

QVariant MyStringListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() >= stringList.size())
        return QVariant();

    if (role == Qt::DisplayRole)
        return stringList.at(index.row());
    else
        return QVariant();
}

обрати внимание:
explicit MyStringListModel(const QStringList &strings, QObject *parent = 0) : QAbstractListModel(parent), stringList(strings) {}
т.е. имя_класса(список_параметров) : (список_инициализаторов_компонентов_данных) {тело_конструктора}
в данном случае переменная stringList инициализируется прямо здесь, тело конструктора пустое.
Xantrax
Цитата(Steklova Olga @ 25.11.2013, 18:26) *
обрати внимание:
explicit MyStringListModel(const QStringList &strings, QObject *parent = 0) : QAbstractListModel(parent), stringList(strings) {}
т.е. имя_класса(список_параметров) : (список_инициализаторов_компонентов_данных) {тело_конструктора}
в данном случае переменная stringList инициализируется прямо здесь, тело конструктора пустое.

Всегда считал, что обе записи имеют право быть. Т.е. можно инициализировать переменные либо в заголовке конструктора, либо в самом конструкторе, не вижу тут ничего криминального.
ilyabvt
Цитата
Всегда считал, что обе записи имеют право быть. Т.е. можно инициализировать переменные либо в заголовке конструктора, либо в самом конструкторе, не вижу тут ничего криминального.

Я вижу. Конструктор должен выполнятся до первого обращения к переменной. Поэтому и придумали список инициализации. Если разрешить обращение к конструктору в теле другого конструктора, то нет гарантий что вызываемый конструктор выполнится до обращения к переменной.
Xantrax
[/quote]
то нет гарантий что вызываемый конструктор выполнится до обращения к переменной.
[/quote]
Если честно, я все равно не понял, ну не выполнится он до обращения к переменной, значит выполнится после... Конструктор всегда выполняется при создании объекта класса..


Цитата(Xantrax @ 25.11.2013, 23:17) *
Цитата

то нет гарантий что вызываемый конструктор выполнится до обращения к переменной.

Если честно, я все равно не понял, ну не выполнится он до обращения к переменной, значит выполнится после... Конструктор всегда выполняется при создании объекта класса..



int QModelIndex::row () const
Returns the row this model index refers to.

Перевожу: врзвращает строку на которую ссылается индекс модели. А на самом деле оказывается - возвращается номер строки...
Анна
Цитата(Xantrax @ 25.11.2013, 23:01) *
Перевожу: врзвращает строку на которую ссылается индекс модели. А на самом деле оказывается - возвращается номер строки...

Не надо особо сильно придираться к тексту, это ведь не англичане пишут. Даже больше скажу, спустя какое-то время стала различать стили авторов разных кусков документации - там есть один, кто в английском вообще не рубит, как только пишет сложно-подчинённое предложение, так вся грамматика накрывается медным тазом, и остаётся только догадываться (или проверять на опыте), что же автор имел ввиду. По int и так понятно, что возвращается не данные всей строки.
Под row во всём, что касается модели и представление, подразумевается номер строки, а под column - номер колонки.

Цитата(Xantrax @ 25.11.2013, 18:25) *
Всегда считал, что обе записи имеют право быть. Т.е. можно инициализировать переменные либо в заголовке конструктора, либо в самом конструкторе, не вижу тут ничего криминального.
В том-то и дело, что вызывая stringList(strings), ты не производишь инициализацию, а пытаешься вызвать конструктор с инициализацией. Когда ты попал в тело конструктора модели, у тебя уже отработал конструктор QStringList() для переменной stringList , а ты вызваешь конструкторещё раз - даже не знаю, что получится, видимо, потому и ругается, что не может пересоздать уже созданное.
Хочется тебе проинициализировать список в теле, пожалуйста, есть много способов, но конструктор-то ещё раз зачем вызывать?

На худой конец, возможет такой вариант:
{
stringList = QStringList(strings);
}
Конечно, если для этого класса реализован оператор =. Но это какой-то совсем по-детски, и опять же, обрати внимание, что даже тут сперва отработал конструктор по умолчанию для stringList , а в теле выполнятся следующие действия: создастся список, который тут же при создании проинициализируется переменной strings, данные из этого списка копируются в stringList, созданный по QStringList(strings) уничтожится при выходе из тела.
Xantrax
Цитата(Анна @ 26.11.2013, 10:29) *
Не надо особо сильно придираться к тексту, это ведь не англичане пишут.
В том-то и дело, что вызывая stringList(strings), ты не производишь инициализацию, а пытаешься вызвать конструктор с инициализацией. Когда ты попал в тело конструктора модели, у тебя уже отработал конструктор QStringList() для переменной stringList , а ты вызваешь конструкторещё раз - даже не знаю, что получится, видимо, потому и ругается, что не может пересоздать уже созданное.

Спасибо, доходчиво.
Litkevich Yuriy
Цитата(Xantrax @ 25.11.2013, 2:45) *
Читаю http://qtdocs.narod.ru/, раздел создание новых моделей...
Эта дока уже заброшена, её немалая часть (спасибо автору перевода) перекочевала сюда
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.