Russian Qt Forum
Июнь 15, 2024, 15:15 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Тонкости InterView  (Прочитано 4504 раз)
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Сентябрь 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, как положено в любом нормальном коде.
Записан

Собираю информацию по крупицам
http://webhamster.ru
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Сентябрь 15, 2010, 21:05 »

считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #2 : Сентябрь 15, 2010, 21:12 »

его видимо не напрягает, а просто он не читал доку внимательно, там и картинка есть
Записан

Юра.
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #3 : Сентябрь 15, 2010, 21:16 »

считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?

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

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

Собираю информацию по крупицам
http://webhamster.ru
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #4 : Сентябрь 15, 2010, 21:18 »

ну так вам надо снаружи вьюхи проверять индекс на валидность и не удалять невалидные индексы. Кроме того, эту проверку можно воткнуть в ваш метод remove(QModelIndex) (это корректно, тк рут удалить нельзя)
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #5 : Сентябрь 15, 2010, 21:21 »

его видимо не напрягает, а просто он не читал доку внимательно, там и картинка есть

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

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

Собираю информацию по крупицам
http://webhamster.ru
BRE
Гость
« Ответ #6 : Сентябрь 15, 2010, 21:27 »

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

Сообщений: 754



Просмотр профиля WWW
« Ответ #7 : Сентябрь 15, 2010, 21:38 »

Ну так корень и есть несуществующий элемент.

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

Собираю информацию по крупицам
http://webhamster.ru
BRE
Гость
« Ответ #8 : Сентябрь 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
« Последнее редактирование: Сентябрь 15, 2010, 22:24 от BRE » Записан
GraninAS
Гость
« Ответ #9 : Сентябрь 28, 2010, 10:11 »

считается что невалидный индекс - это корень. Чем вас это соглашение напрягает?

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

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

В древовидной структуре удаление должно быть рекурсивным, тогда проблем не возникнет.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.113 секунд. Запросов: 19.