Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Igors от Март 23, 2018, 15:56



Название: Перехват update
Отправлено: Igors от Март 23, 2018, 15:56
Добрый день

Есть большая таблица с массой ф-ционала. Многие действия юзера вызывают вставку/удаление строк из таблицы. Суетиться на каждое - тормоза, поэтому кеширую изменения и посылаю событие. Там в обработчике все меняю "скопом" и вызываю update окна. Вроде все путем, но иногда каким-то образом прорывается update и начинается отрисовка строк данные которых уже удалены. Ладно, в paintEvent проверяю пуст ли кеш изменений, и если нет - выхожу из paint'а вон.  Это неаккуратно, иногда видно "подмигивание", да и лишняя перерисовка "не украшает" при хорошем размере данных. Как сделать чисто?

Доп инфа. Таблица - наследник QWidget, не имеет никакого отношения к QTableWidget и.т.п. Рассматривал QWidget::setUpdatesEnabled, но не вижу как его здесь заюзать. Было бы здОрово поставить breakpoint на update но как это сделать именно для данной таблицы?

Спасибо


Название: Re: Перехват update
Отправлено: GreatSnake от Март 24, 2018, 15:44
Было бы здОрово поставить breakpoint на update но как это сделать именно для данной таблицы?
Без толку, т.к. отрисовка всё-равно асинхронная.


Название: Re: Перехват update
Отправлено: Igors от Март 26, 2018, 09:55
Попробовал проигнорировать QEvent::UpdateRequest (т.е. если окно не валидно - рисование пропускаем). НЕ работает. Попробовал setUpdatesEnabled - (при первом заполнении кеша false, когда сбросил кеш - true). Тоже НЕ работает. Как-то мне с этим setUpdatesEnabled все время не везет, пока ни разу не удалось его приспособить.

В обоих случаях окно остается замороженным, и оживает после возюкания мыши (может при смене курсора, хз). Ставлю тестовый qDebug(), печатается как положено и все работает как и было задумано. Мда, хреновато...


Название: Re: Перехват update
Отправлено: Igors от Апрель 01, 2018, 12:25
Отловил ситуацию когда окно НЕ перерисовывается после setUpdatesEnabled(true) - когда окно теряет фокус, напр бубочка (вызывающая setUpdatesEnabled) нажимается из др окна. Тогда UpdateRequest не посылается, судя по исходникам, окно уже "dirty".

Ладно, нашел такой workaround: делаю setUpdatesEnabled не для окна, а для его виджета, т.е. большой таблицы. Это срабатывает всегда, но.. после этого следующий вызов window->update() (т.е для окна) уже не перерисовывает таблицу  :'(  Приходится и там апдейтить таблицу (а не окно)



Название: Re: Перехват update
Отправлено: Авварон от Апрель 06, 2018, 21:32
Уапрос, насколько частые вставки? Мы в свое время решали похожую задачу на айтемвьюхах, там были ОЧЕНЬ частые обновления и ОЧЕНЬ много данных.


Название: Re: Перехват update
Отправлено: Igors от Апрель 07, 2018, 12:09
Уапрос, насколько частые вставки? Мы в свое время решали похожую задачу на айтемвьюхах, там были ОЧЕНЬ частые обновления и ОЧЕНЬ много данных.
Ну "тысячи" - дело рядовое (напр объекты читаются из файла). Хотя в прынцыпе - какая разница, главное > 1


Название: Re: Перехват update
Отправлено: Авварон от Апрель 07, 2018, 19:34
"Тысячи" чего? rps какой? Тысячи в час и в секунду - разная вещь.


Название: Re: Перехват update
Отправлено: Igors от Апрель 08, 2018, 05:48
"Тысячи" чего? rps какой? Тысячи в час и в секунду - разная вещь.
Чего = вставок (Вы же о них спрашивали). За какое время - хз, ну пока все объекты не будут считаны с диска.

Кстати, такая ситуация: посылается сигнал с QueuedConnection, до этого возможно были update(), но в событийный цикл не выходили. Вопрос: гарантируется ли что слоты сигнала сработают ДО рисования?


Название: Re: Перехват update
Отправлено: Авварон от Апрель 09, 2018, 14:46
А зачем вы уведомляете вью на каждую вставку? Реализуйте механизм аналогичный BeginResetModel/EndResetModel - на EndResetModel просто перечитывать видимое состояние модели и перерисовать всё один раз.


Название: Re: Перехват update
Отправлено: Igors от Апрель 10, 2018, 06:57
А зачем вы уведомляете вью на каждую вставку? Реализуйте механизм аналогичный BeginResetModel/EndResetModel - на EndResetModel просто перечитывать видимое состояние модели и перерисовать всё один раз.
Не видел этого механизма, да и моменты Begin/End известны далеко не во всех случаях. Я кручу такой сюжетик

- окно получает запрос на вставку (удаление, изменение, и.т.п.). Запрос запоминается, перерисовка блокируется и, если это первый запомненный запрос, посылается сигнал "обновить данные" с QueuedConnection

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

Да, какие-то update могут просочиться как до первого запроса, так и после - но отловить их нереально. Вроде как классический случай блокировки рисования - но штатное средство не работает как положено  :'(


Название: Re: Перехват update
Отправлено: Авварон от Апрель 10, 2018, 17:06
Я не очень понимаю, причем тут кьювед коннекшн.
Пришли данные большой пачкой (файл) - положили их в модель, уведомили вью о том, что надо всё перерисовать.
Пришли данные маленькой пачкой (из формочки или днд) - уведомили вью что надо обновить кусочек.

Как я понимаю, сейчас уведомление идет на каждый чанк (строку) данных из файла - это и надо поправить сперва.


Название: Re: Перехват update
Отправлено: Igors от Апрель 11, 2018, 09:44
Я не очень понимаю, причем тут кьювед коннекшн.
Пришли данные большой пачкой (файл) - положили их в модель, уведомили вью о том, что надо всё перерисовать.
Пришли данные маленькой пачкой (из формочки или днд) - уведомили вью что надо обновить кусочек.

Как я понимаю, сейчас уведомление идет на каждый чанк (строку) данных из файла - это и надо поправить сперва.
Нету там никакого model-view (в терминах Qt). Что впрочем ничего не меняет. Фактически модель - вектор, на каждый чих дергать - уже плохо. Пачек тоже нету - приходят по одному, просто напр при чтении файла их может оказаться много (до выхода в событийный цикл). Поэтому "уведомление" лучше организовать самому, вот и QueuedConnection


Название: Re: Перехват update
Отправлено: Авварон от Апрель 11, 2018, 13:25
Ну вот советую сделать модель-вид. Всё же, их не в Qt придумали:)
Если вы посмотрите на QTextEdit - это тот же model-view (и даже контроллер там есть внутре).
Дергать вектор на каждый чих легко и приятно:) Если объемы данных ну очень большие, то можно заюзать std::deque, у ей внутре чанки, а значит вставка в середину быстрее, чем у вектора.
Но опять же, ничто не мешает вставить в конец вектора и отсортировать.


Название: Re: Перехват update
Отправлено: Igors от Апрель 11, 2018, 14:30
Дергать вектор на каждый чих легко и приятно:) Если объемы данных ну очень большие, то можно заюзать std::deque, у ей внутре чанки, а значит вставка в середину быстрее, чем у вектора.
Но опять же, ничто не мешает вставить в конец вектора и отсортировать.
Ну такие соображения не принципиальны, кеширование - прием фундаментальный, и тратить время чтобы как-то обойтись без него не стоит. Текущее решение совершенно нормально, вот почему штатная блокировка рисования глючит - вот вопрос.

Ну вот советую сделать модель-вид. Всё же, их не в Qt придумали:)
Никогда не верил в этот магический модель-вид  :) Куча людей повторяет что-то типа "модель хранит, вьюха отображает!" (какой пассаж), но по-моему реально за этим ничего не стоит. Ну хорошо, вот допустим было бы у меня "по всем канонам", model-view (опись, протокол, отпечатки пальцев) и.. что с того?
положили их в модель, уведомили вью
Это не годится ни так ни сяк.


Название: Re: Перехват update
Отправлено: Авварон от Апрель 11, 2018, 14:48
Никогда не верил в этот магический модель-вид  :) Куча людей повторяет что-то типа "модель хранит, вьюха отображает!" (какой пассаж), но по-моему реально за этим ничего не стоит. Ну хорошо, вот допустим было бы у меня "по всем канонам", model-view (опись, протокол, отпечатки пальцев) и.. что с того?

Вам не пришлось бы мутить с отложенными событиями, которые куда-то там "прорываются".


Название: Re: Перехват update
Отправлено: Авварон от Апрель 11, 2018, 14:50
Ну а по сабжу - update() не вызывает перерисовку, а кладёт запрос на неё в очередь, т.е. paintEvent() и update() - вещи разные.
Можно попробовать отловить, откуда идёт paintEvent()


Название: Re: Перехват update
Отправлено: Igors от Апрель 12, 2018, 18:09
Вам не пришлось бы мутить с отложенными событиями, которые куда-то там "прорываются".
Если я хочу (а я хочу) отложить обновление модели (а не вью) - все то же самое. В Qt есть нечто подобное (метод IsChanging, в букварь не вошел), но используется только для пресечения сортировки.
Ну а по сабжу - update() не вызывает перерисовку, а кладёт запрос на неё в очередь, т.е. paintEvent() и update() - вещи разные.
Предлагаю считать собеседников достаточно грамотными  :)
Можно попробовать отловить, откуда идёт paintEvent()
Из QEvent::UpdateRequest которое засылается тем самым update(). Перед вызовом paint вью апдейтит айтемы опираясь, однако, на модель - она должна быть валидна.

Место где пропускается засылка UpdateRequest я конечно давно нашел
Код
C++ (Qt)
void QWidgetBackingStore::markDirty(const QRect &rect, QWidget *widget,
                                   UpdateTime updateTime, BufferState bufferState)
....
  const QRect translatedRect(widgetRect.translated(widget->mapTo(tlw, QPoint())));
   if (qt_region_strictContains(dirty, translatedRect)) {
       if (updateTime == UpdateNow)                  // сюда заходит, но updateTime == UpdateLater
           sendUpdateRequest(tlw, updateTime);   // не выполняется
       return; // Already dirty
   }
 
Вероятно буги-вуги. Кто-то маркировал dirty но UpdateRequest или не был послан или не имел эффекта, т.к. setUpdatesEnabled стояло в false. А данный код понадеялся на это и тоже запрос не послал. И шо делать?


Название: Re: Перехват update
Отправлено: Авварон от Апрель 12, 2018, 18:15
Цитировать
// сюда заходит, но updateTime == UpdateLater

Ну это значит, что регион уже был добавлен ранее, что не говорит как бы ниачом.
Я так понимаю, что оно просто копит dirty регионы и когда updatesEnabled отпускается, вызывает update()/paintEvent()


Название: Re: Перехват update
Отправлено: Igors от Апрель 12, 2018, 18:25
Я так понимаю, что оно просто копит dirty регионы и когда updatesEnabled отпускается, вызывает update()/paintEvent()
Не совсем. По идее как только появился первый dirty - QEvent::UpdateRequest уже в очередь полетело. А дальше копит до того как будет очищено перерисовкой.


Название: Re: Перехват update
Отправлено: Авварон от Апрель 12, 2018, 19:05
А если мы выйдем в очередь случайно?


Название: Re: Перехват update
Отправлено: Igors от Апрель 13, 2018, 08:59
А если мы выйдем в очередь случайно?
setUpdatesEnabled(false) не позволит рисовать если модель еще не обновленв