Russian Qt Forum

Qt => Вопросы новичков => Тема начата: nvek от Декабрь 24, 2017, 10:40



Название: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 24, 2017, 10:40
В документации сказано что надо обновление своей структуры заносить в
Код:
beginInsertRow()
addChild()
endInsertRow()
но, если делать
Код:
addChild()
beginInsertRow()
endInsertRow()
или же
Код:
beginInsertRow()
endInsertRow()
addChild()

будет ошибка, даже если это делать в одной и той же функции.
почему? как это работает?


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: Авварон от Декабрь 24, 2017, 12:46
При удалении, например, перерасчитывается выделенная строка - если она попала в удаленную область (напирмер, удаляем индексы 5-9), то её надо подвинуть на первый индекс после области (или на парента, если области нет) (10й).
Если вы сперва удалите данные, а потом кинете сигнал, то методы index() и parent() для модели будут давать неверные данные - вью запрашивает 10й индекс, а его уже нет (он теперь 5й).
Если вы сперва кинете сигналы, а потом удалите данные, то будет неверно вызвана отрисовка - на момент отрисовки вью считает, что индексов нет, а они ещё есть. Т.е. она отрисует старые данные и не отрисует часть оставшихся.
И это только глядя на QAbstractItemView (https://github.com/qt/qtbase/blob/5.10/src/widgets/itemviews/qabstractitemview.cpp#L3363), в случае того же QTreeView надо пересчитывать внутреннюю таблицу, которая живет в нём.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 25, 2017, 13:58
понимаю почему, но не понимаю как  ???


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 25, 2017, 14:22
опять же, есть простой метод:
Код:
 
//...
emit serv->sg_removeChildren(1, i, pThis);
emit serv->sg_endDeleteRow();

m_childItems.remove(i);
//...


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


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: kuzulis от Декабрь 25, 2017, 14:42
Не надо ничего вьюшке говорить, т.к. модель сама скажет ей. Именно поэтому нужно все делать в правильном порядке с begin/end.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 25, 2017, 16:28
да, в правильном, не спорю, интересен другой вопрос, как это все происходит?


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: deMax от Декабрь 26, 2017, 08:39
Предположу: т.к. данные в моделе могут вообще не храниться(например таблица умножения). Компилятору нужно понять когда в таблице что то измениться чтобы пересчитать данные для отображения.
begin - сохраняет первоначальное состояние, end - смотрит нужные изменения(если insert то значит только добавляли) и обновляет в отображение только то что изменилось.
можно один refresh - но тогда придется для всех ячеек вызвать получение новых данных и обновлять всю таблицу. Тогда при удалении строк в самом начале(вне видимости виджета) таблица будет смещена.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 26, 2017, 13:20
смотрю в исходниках как все идет
beginRemoveRow(){если правильно понимаю, там просиходит добавление в стек тех индексов. которые подвержены изменению (те самые индексы, которые мы подали)} посылает сигнал -> emit rowsAboutTobeRemoved(const QModelIndex& parent, int first, int last)
а затем вызывает свой метод
rowsAboutTobeRemoved(const QModelIndex& parent, int first, int last)
смысл такой, что в endRemoveRows()
в конце вызывается метод removeRow() и после него
emit removeRow()

эти сигналы соединены с QAbstractItemViewPrivate
то есть с нашим представлением видимо, внутри этих сигналов
идет запоминание индексов, затем ихнее удаление

но все равно не понимаю, вначале идет begin потом end
все вроде удалилось. дальше я удаляю из своей структуры
m_childItems.remove(i);
поидее , если синхронизировать это с тем, чтобы rowCount показывал на единицу меньше, то все должно работать.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: Авварон от Декабрь 26, 2017, 18:53
Ну, если rowCount/index/parent/data будут возвращать новые данные, то всё будет ок:)


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 28, 2017, 06:47
вот у меня не работает. Падает на паренте при перерисовке. в Парент приходит невалидный указатель по валидному индексу.
Как это работает???  ???  ???
И это случается я так думаю из-за хавера, который елозит по treeView


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 28, 2017, 07:06
Опять же повторюсь, что при правильном подходе все работает правильно, но мне безумно интересно, почему. Уже второй день мучию исходники qt


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 28, 2017, 07:58
точно знаю, что в этом всем деле, замешан hover
Код:
//qtreeview.cpp QTreeView::drawRow
const bool hoverRow = selectionBehavior() == QAbstractItemView::SelectRows
                  && index.parent() == hover.parent()
                  && index.row() == hover.row();
ведь это именно он вызывает метод парент.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: Igors от Декабрь 28, 2017, 08:56
.. но мне безумно интересно, почему..
Это пройдет. Пользуясь либой вы/мы неизбежно в какой-то мере становимся "пользователями". Т.е. не нужно вдаваться в подробности отчего да почему если все работает как положено. Это нормально, главное не слишком увлекаться, не сваливаться в бездумную жратву чужих классов. Ну найдете, ну осознаете - да, "полезно", но особого понимания это не добавит.


Название: Re: Как работает BeginINsertRow и ему подобные?
Отправлено: nvek от Декабрь 28, 2017, 10:37
Возможно ли такое, что все может быть еще связано с таймером?
данные обновляются по таймингу. Таймер же как я прочитал в книге, полностью ассинхронный.
проверял, с евента, мышки до перерисовки вьюшки идет все в одном потоке.
Залезая в исходники qt я только все больше постигаю черную магию
А может быть такое, что сигналы как-то на системных прерываниях работают?