Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Igors от Апрель 14, 2015, 12:43



Название: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 12:43
Добрый день

Есть несколько окон с OpenGL рисование которых может быть достаточно долгим. Когда юзер что-то изменил  я вызываю update для всех окон нуждающихся в перерисовке, в результате получаю paintEvent. И вот когда юзер- пулеметчик выбирает слишком быстро - получается эффект засорившейся сливной трубы. Напр за секунду он успел что-то изменить 4 раза, за это время еще и первое обновление не успело. Потом рисуется второе нажатие и.т.д. А надо рисовать сразу 4-е, последнее. Как этого добиться?

Спасибо


Название: Re: Очередность событий
Отправлено: Swa от Апрель 14, 2015, 13:07
Первое что приходит на ум - задержка. Рендер запускается через, например, 0,5 - 1 сек с последнего действия юзера.


Название: Re: Очередность событий
Отправлено: Bepec от Апрель 14, 2015, 13:48
Менеджер обновления, самый простейший  как и предложили обновление по таймеру. Ну или заморочиться с очередями.


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 14:05
Я бы использовал очереди и таймер


Название: Re: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 14:22
Не в первый раз наблюдаю этот эффект - какое-то решение предложено (причем автор даже не говорил "хорошее"), и оно тут же одобряется, без всякого осмысления  :)

А если объект двигать надо, то как, рывками через пол-секунды? А если геометрии мало или карта приличная? Наверное надо "подбирать скорость", интервал (ох и долго тут один про это спрашивал, до сих пор помню "Это все ясно, но какая ..."  - и так N раз :)) 

Мужчины, ну как-то все-таки думать надо  :)


Название: Re: Очередность событий
Отправлено: Bepec от Апрель 14, 2015, 14:27
Если надо то двигайте. А так четко поставлена задача - проредить поток перерисовок от пользователя.
Там хоть 100 хоть 1кк событий перерисовки быть может. А время перерисовки мы не знаем и рассчитать не можем. Следовательно сделать движение объекта "плавным" мы не в силах.

И вообще - мы говорим о перерисовке. Пользун что то поменял - нужно перерисовывать всё, в том числе и этот ваш движущийся объект, ибо он "старый".

PS конкретизируйте тогда свои требования, у вас с этим проблема если честно. Если вам нужна плавная картинка с постоянно меняющимися параметрами и полным интерактивом, мб стоит тогда подумать о наращивании мощности железа, а не ловле блох с невнятными требованиями?


Название: Re: Очередность событий
Отправлено: Swa от Апрель 14, 2015, 14:28
Не в первый раз наблюдаю этот эффект - какое-то решение предложено (причем автор даже не говорил "хорошее"), и оно тут же одобряется, без всякого осмысления  :)

А если объект двигать надо, то как, рывками через пол-секунды? А если геометрии мало или карта приличная? Наверное надо "подбирать скорость", интервал (ох и долго тут один про это спрашивал, до сих пор помню "Это все ясно, но какая ..."  - и так N раз :))  

Мужчины, ну как-то все-таки думать надо  :)

Вы не описали подробно условия задачи, а говорите что решение вам не подходит.
В первом посте было: "И вот когда юзер- пулеметчик выбирает слишком быстро" - из этого я сделал вывод, что пользователь набирает текст. Для этой ситуации, ИМХО, таймер подходит.
Если у вас не только набор текста, опишите подробнее, как устроен софт и чего нужно добиться.


Название: Re: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 14:50
Если у вас не только набор текста, опишите подробнее, как устроен софт и чего нужно добиться.
Случаев много, один из них: объекты отображаются в неск окнах, есть еще окно со списком объектов. Юзер может выбирать из списка кликнув на айтем мышей, выбранный объект должен подсветиться во всех окнах - вот собственно и все.

Кстати - а ведь еще давным-давно читал что меседж WM_PAINT "имеет низший приоритет", чего же оно приходит раньше события нажатия? Может это только на Вындоуз? Ой вряд ли. Вообще в Qt 5 не знаю как посмотреть события, он как-то складывает их сначала себе а потом диспатчит из своей очереди. Это может совсем не соответствовать "событиям-первоисточникам" что послал ОС 


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 14:51
ИМХО, какая разница, что там - текст, не текст. Каждые 1/60 секунды вызывать таймер, который будет проверять наличие необходимости в перерисовке. Это приведёт к уменьшению рывков, возможно к ликвидации.


Название: Re: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 14:57
ИМХО, какая разница, что там - текст, не текст. Каждые 1/60 секунды вызывать таймер, который будет проверять наличие необходимости в перерисовке. Это приведёт к уменьшению рывков, возможно к ликвидации.
Вы не можете вызывать таймер, а только получать события от него, причем они придут только если нет никаких др событий. Поэтому в примере выше таймер получите когда выполнены все 4 перерисовки


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 15:07
Таймер вызывает 1 перерисовку. Даже если вы внесли 4 изменения, то они входят в эту 1 перерисовку. Поэтому он "глушиться" большим количеством перерисовок не может. Действия пользователя обрабатываются за кадром.


Название: Re: Очередность событий
Отправлено: Bepec от Апрель 14, 2015, 15:16
Тут прикол в том, что перерисовка может занимать не 20 мс, а неизвестное количество времени :D


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 15:39
В упор не понимаю.
Ну пусть отрисовывается 10 секунд. Я натыкал 200 раз по окну, после перерисовки они вступают в силу на уровне мозгов. Пришло время следующей перерисовки по таймеру и эти 200 изменений появляются на экране.
Я что-то не так понимаю?


Название: Re: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 16:04
В упор не понимаю.
Ну пусть отрисовывается 10 секунд. Я натыкал 200 раз по окну, после перерисовки они вступают в силу на уровне мозгов. Пришло время следующей перерисовки по таймеру и эти 200 изменений появляются на экране.
Я что-то не так понимаю?
Кто (или куда) должен прийти? Сейчас схема такая (значимые события)

QEvent::MouseButtonPress  (1) // юзер выбрал айтем, делаем update всем окнам 
QEvent::Paint   (1)  // рисуем окно 1
QEvent::Paint   (2)  // рисуем окно 2
...
QEvent::Paint   (last)  // рисуем последнее окно
QEvent::MouseButtonPress  (2)  // юзер опять выбрал айтем, все по новой

Беда в том что когда отработывает первый Paint шустрый юзер уже успел понатыкать раза 3-4. Можно отложить update и сделать его по таймеру, но минусы этого решения очевидны. Хотелось бы получить MouseButtonPress  (2) сразу после QEvent::Paint   (1), ведь рисовалось долго и нажатие уже состоялось. Но (хз почему) не получаю


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 16:45
Хотелось бы получить MouseButtonPress  (2) сразу после QEvent::Paint   (1), ведь рисовалось долго и нажатие уже состоялось. Но (хз почему) не получаю
То есть, нажатия пользователя проглатываются перерисовкой? Это, действительно, странно


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 16:50
А, понял.

Дык это нормально, что нельзя вклиниться так просто между первой и второй прорисовкой, имхо.
Что если между перерисовками воткнуть QCoreApplication::processEvents? Далее отслеживаем, был ли клик/тык, а там уже отменяем текущую перерисовку и начинаем всё заново.
Быть может это поможет...


Название: Re: Очередность событий
Отправлено: Igors от Апрель 14, 2015, 17:49
Дык это нормально, что нельзя вклиниться так просто между первой и второй прорисовкой, имхо.
ИМХО нет - почему более важное событие (нажатие мыши) следует после менее важного (перерисовки). Да, запрос на перерисовку (update) был послан раньше, но ведь его приоритет ниже

Что если между перерисовками воткнуть QCoreApplication::processEvents? Далее отслеживаем, был ли клик/тык, а там уже отменяем текущую перерисовку и начинаем всё заново.
А как "воткнуть между" - ведь рисование это обработчик события, просить в нем еще события = верный ппц


Название: Re: Очередность событий
Отправлено: __Heaven__ от Апрель 14, 2015, 18:02
Почему вы считаете нажатие мыши более приоритетным событием, чем запрос перерисовки?
Я понимаю, что они обрабатываются в одном потоке и пока не завершится один процесс - другой не сможет вмешаться.

Я вижу себе что-то вроде такого:

Код
C++ (Qt)
void fullUpdate()
{
   for (int i = 0; i < 4; ++i)
   {
       QCoreApplication::processEvents();       // тут у нас отмечается флаг активности пользователя / срабатывает мышь
       if (userEvent)
            break;
       window[i].upd();
   }
}

Цикл перерисовок прерывается, таймер видит, что у вас активен флаг userEvent, обнуляет его и запускает fullUpdate.


Название: Re: Очередность событий
Отправлено: Igors от Апрель 15, 2015, 05:46
Почему вы считаете нажатие мыши более приоритетным событием, чем запрос перерисовки?
Ну как бы "впитал с молоком матери"  :)

Я понимаю, что они обрабатываются в одном потоке и пока не завершится один процесс - другой не сможет вмешаться.
Давайте терминов придерживаться. Процесс - это тот у которого свое адресное пр-во.

Так, ну с таймером все-таки получается. Вместо того чтобы сразу делать update всем окнам их надо сохранить в списке. Событие таймера извлекает указатель на окно из списка и делает ему update. А событие мыши заполняет список.

Ну как-то я не в восторге. Конечно update растыкан в сотнях мест, не вижу как его глобально переопределить. И update вызывается еще и контролами Qt - тоже надо учитывать. Попробую сначала сделать пример, там посмотрим


Название: Re: Очередность событий
Отправлено: AlexEx от Апрель 15, 2015, 12:52
Конечно, MouseButtonPress нет, ибо GUI-шный поток один и занят в это время Paint'ом. Похоже, надо дробить Paint на части (если возможно). Аналогично тому, как иногда картинки прорисовывают - сперва одни группы точек по всей площади картинки, затем другие группы и т.д.


Название: Re: Очередность событий
Отправлено: qate от Апрель 15, 2015, 13:22
0. флаг необходимости перерисовки сброшен
1. поступило событие что надо перерисовать - если флаг установлен то выход; иначе ставим флаг и таймер на 20 мсек singleshot и выход
3. таймер cработал - перерисовка, сброс флага


Название: Re: Очередность событий
Отправлено: Igors от Апрель 15, 2015, 14:38
Конечно, MouseButtonPress нет, ибо GUI-шный поток один и занят в это время Paint'ом.
Так и следующее событие - тоже paint (теперь уже другого окна), а хотелось бы сначала press

Похоже, надо дробить Paint на части (если возможно).
С OpenGL нет

0. флаг необходимости перерисовки сброшен
1. поступило событие что надо перерисовать - если флаг установлен то выход; иначе ставим флаг и таймер на 20 мсек singleshot и выход
3. таймер cработал - перерисовка, сброс флага
А как Вы будете рисовать в событии таймера?


Название: Re: Очередность событий
Отправлено: qate от Апрель 15, 2015, 15:34
> А как Вы будете рисовать в событии таймера?

вот взял и рисовал на QGraphicsScene по таймеру как и описал
а для OpenGL нельзя по событию таймера рисовать ?


Название: Re: Очередность событий
Отправлено: Igors от Апрель 15, 2015, 16:18
> А как Вы будете рисовать в событии таймера?

вот взял и рисовал на QGraphicsScene по таймеру как и описал
а для OpenGL нельзя по событию таймера рисовать ?
Там мутность великая :) Надо устанавливать контекст, причем просто makeCurrent (как сделал бы нормальный человек) не катит. И контекст не будет создан до первого рисования.

А вообще в букваре пишут что низзя, рисуйте только из paintEvent! И для обычных виджетов так и есть, не создается painter вне paintEvent. И для обычных просто так не пропустить событие рисования (отдаваясь в таймер) т.к. background уже зачищен и экран обновится "при любой погоде"


Название: Re: Очередность событий
Отправлено: qate от Апрель 15, 2015, 16:56
А вообще в букваре пишут что низзя, рисуйте только из paintEvent!

мое рисование было - это добавление на сцену элементов сцены (additem, прямоугольники, текст, заливка) - поэтому их можно в таймере

но не проблема и в paintEvent:
0. флаги "МожноРисовать" и "НужноРисовать"  сброшены
1. поступило событие что надо перерисовать - если флаг "НужноРисовать"  установлен то выход; иначе ставим флаг "НужноРисовать"  и таймер на 20 мсек singleshot и выход
3. таймер cработал - "МожноРисовать" устанавливаем
4. в paintEvent смотрим "МожноРисовать" , если не установлен - выход. если установлен - рисуем и сбрасываем оба флага (мутексы по месту ставим)