Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: xintrea от Сентябрь 15, 2010, 20:54



Название: Тонкости InterView
Отправлено: xintrea от Сентябрь 15, 2010, 20:54
Здравствуйте!


Всем нам известен режим связывания модели и представления, который в Qt называется InterView. В SDK есть готовые примеры. И что-то я не могу понять одной вещи.

Есть два метода (можно посмотреть в примере):

Код
C++ (Qt)
int TreeModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem = getItem(parent);
    return parentItem->childCount();
}
 
TreeItem *TreeModel::getItem(const QModelIndex &index) const
{
    if (index.isValid()) {
        TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
        if (item) return item;
    }
    return rootItem;
}

Так вот, в rowCount() нет проверки на валидность индекса. В результате, даже если индекс невалидный, из rowCount() идет тупо вызов getItem().

В getItem() в случае невалидного индекса возвращается rootItem (!) - зачем??

Но самое интересное возникает тогда, когда пытаешься добавить проверку валидности в rowCount(). Например так:

Код
C++ (Qt)
int TreeModel::rowCount(const QModelIndex &parent) const
{
if(parent.isValid()) {
  TreeItem *item = getItem(parent);
  return item->childCount();
 }
else return 0;
}

После такого исправления, дерево перестает отображаться вообще. Дебаг показал, что это происходит из-за того, что представление запрашивает количество строк в корне дерева путем запрашивания у модели метода rowCount(), передавая ему невалидный индекс (!) . И ожидает, что если индекс невалидный, то будет возвращено количество строк корневого элемента (а не 0). Зачем так??

Я хотел переделать getItem() таким образом, чтобы он возвращал NULL а не rootItem в случае невалидного индекса. Но оказывается, это сделать нельзя по вышеописанной причине.

Вопрос - почему так сделано, и есть ли какой-нибудь способ правильно работать с невалидными индексами? То есть не возвращать rootItem в случае невалидного индекса, а возвращать NULL, как положено в любом нормальном коде.


Название: Re: Тонкости InterView
Отправлено: Авварон от Сентябрь 15, 2010, 21:05
считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?


Название: Re: Тонкости InterView
Отправлено: lit-uriy от Сентябрь 15, 2010, 21:12
его видимо не напрягает, а просто он не читал доку внимательно, там и картинка (http://doc.crossplatform.ru/qt/4.6.x/model-view-model.html) есть


Название: Re: Тонкости InterView
Отправлено: xintrea от Сентябрь 15, 2010, 21:16
считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?

Тем, что например при удалении веток в дереве, если пользователем помечена она ветка и пара ее же подветок (глупо, но такая ситуация возможна), то к моменту удаления подветки у нее получается невалидный индекс (ибо родительская ветка уже удалена).

Связанные с веткой данные должны очищаться через, например, setData(). Но setData тоже работает через getItem(), а getItem() возвращает корень дерева в случае невалидного индекса. И происходит удаление данных в корне.


Название: Re: Тонкости InterView
Отправлено: Авварон от Сентябрь 15, 2010, 21:18
ну так вам надо снаружи вьюхи проверять индекс на валидность и не удалять невалидные индексы. Кроме того, эту проверку можно воткнуть в ваш метод remove(QModelIndex) (это корректно, тк рут удалить нельзя)


Название: Re: Тонкости InterView
Отправлено: xintrea от Сентябрь 15, 2010, 21:21
его видимо не напрягает, а просто он не читал доку внимательно, там и картинка (http://doc.crossplatform.ru/qt/4.6.x/model-view-model.html) есть

Не, когда сказали - я вспомнил, просто год с Qt не возился, все позабыл.

На лицо неправильная объектная декомпозиция, в которой смешаны понятия "корень" и "несуществующий элемент".


Название: Re: Тонкости InterView
Отправлено: BRE от Сентябрь 15, 2010, 21:27
На лицо неправильная объектная декомпозиция, в которой смешаны понятия "корень" и "несуществующий элемент".
Ну так корень и есть несуществующий элемент.


Название: Re: Тонкости InterView
Отправлено: xintrea от Сентябрь 15, 2010, 21:38
Ну так корень и есть несуществующий элемент.

Нет, корень - это корень. Можете считать его особым несуществующим элементом. Должна быть возможность отличать корень и несуществующий элемент. А такой возможности нет.


Название: Re: Тонкости InterView
Отправлено: BRE от Сентябрь 15, 2010, 22:03
Нет, корень - это корень. Можете считать его особым несуществующим элементом. Должна быть возможность отличать корень и несуществующий элемент. А такой возможности нет.
Да как бы все проще.
С точки зрения QModelIndex, не валидный индекс это индекс с row < 0 или column < 0 или model == 0.
Такой индекс можно создать вызвав конструктор по умолчанию, а он (не считая конструктора копирования) единственный публичный.
При его передачи в качестве parent, считается что имеется ввиду root элемент.

Это я к чему, что проверка isValid покажет true, для созданного индекса даже если такого элемента уже нет, главное что бы соблюдалось вышеуказанное условие.

А для проверки корректности ячейки можно попробовать использовать метод:
bool QAbstractItemModel::hasIndex ( int row, int column, const QModelIndex & parent = QModelIndex() ) const


Название: Re: Тонкости InterView
Отправлено: GraninAS от Сентябрь 28, 2010, 10:11
считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?

Тем, что например при удалении веток в дереве, если пользователем помечена она ветка и пара ее же подветок (глупо, но такая ситуация возможна), то к моменту удаления подветки у нее получается невалидный индекс (ибо родительская ветка уже удалена).

Связанные с веткой данные должны очищаться через, например, setData(). Но setData тоже работает через getItem(), а getItem() возвращает корень дерева в случае невалидного индекса. И происходит удаление данных в корне.

В древовидной структуре удаление должно быть рекурсивным, тогда проблем не возникнет.