Название: Перехват 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 я конечно давно нашел Код Вероятно буги-вуги. Кто-то маркировал 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) не позволит рисовать если модель еще не обновленв |