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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Обновление(перерисовка) состояния виджетов. set*** и update(). Вопрос. Qt 4.5.0  (Прочитано 33040 раз)
Danila_Bagrofff
Гость
« : Октябрь 02, 2009, 13:00 »

Мы можем любому виджету изменить текст, картинку, что угодно с помощью различных методов, как то setText(), setPixmap() и.т.д.

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

Это результат того, что событие отрисовки для данного виджета встало в очередь событий? Метод update() с последующий QApplication::processEvents() вызовет мгновенную отработку отрисовки? Правильно?

И еще вопрос. Если в собственном обработчике событий, возникает другое событие, в том числе и по перерисовке элементов интерфейса, то все последующие события встанут в очередь событий? processEvent сможет прервать его для обновления перерисовки? Или я не правильно понимаю логику Qt?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Октябрь 02, 2009, 13:23 »

Ну здесь легко "залезть в дебри" Улыбающийся В общих чертах: update() мгновенной перерисовки не обещает, если есть такая необходимость - нужно использовать repaint()

Запрос на перерисовку помещается в системную очередь событий и его приоритет ниже других событий, т.е. пришедшие позже события могут выполняться до перерисовки. OS может объединять/сливать несколько  перерисовок в одну. С обновлением экрана (видеопамяти) тоже не все просто, некоторые OS держат окна "double-buffered" и имеют еще один уровень "выталкивания" в видео. Например, если Вы нарисуете синий квадрат, а затем поверх него красный, на одних OS это будет мигать а на других нет. В общем это очень большой огород и вникать во все нюансы может и не стоит.
Записан
Danila_Bagrofff
Гость
« Ответ #2 : Октябрь 02, 2009, 13:53 »

Хорошо, как правильно обновлять тогда? Что лучше использовать?

Правильно вызывать processEvents? Чтобы протолкнуть вызов события перерисовки? Или repaint() выполнит это сам?

Как вариант ведь можно использовать вызов update() по таймеру.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Октябрь 02, 2009, 15:15 »

Хорошо, как правильно обновлять тогда? Что лучше использовать?

Правильно вызывать processEvents? Чтобы протолкнуть вызов события перерисовки? Или repaint() выполнит это сам?

Как вариант ведь можно использовать вызов update() по таймеру.
1) update() по таймеру ничего не дает, т.к. update только засылает запрос на перерисовку в очередь

2) processEvents здесь ничего не ускорит

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

Итого: надо вставить repaint() в те места, где идут тяжелые расчеты и перерисовка не успевает. Допустим один раз на 100 вычислений в цикле (или на 1000, подобрать).
Записан
Danila_Bagrofff
Гость
« Ответ #4 : Октябрь 05, 2009, 06:55 »

А использование  setUpdatesEnabled() поочередно ведь тоже можно испрользовать, насколько я понимаю?
{
...
 setUpdatesEnabled(true);
 repaint();
 setUpdatesEnabled(false);
...
}

Чтобы не было ненужных перерисовок, а все перерисовки при сложных вычислениях шли только по repaint'у.

Так верно - или это будет излишним?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Октябрь 05, 2009, 08:57 »

А использование  setUpdatesEnabled() поочередно ведь тоже можно испрользовать, насколько я понимаю?
{
...
 setUpdatesEnabled(true);
 repaint();
 setUpdatesEnabled(false);
...
}

Чтобы не было ненужных перерисовок, а все перерисовки при сложных вычислениях шли только по repaint'у.

Так верно - или это будет излишним?
100% верно и чище
Записан
Danila_Bagrofff
Гость
« Ответ #6 : Октябрь 05, 2009, 12:55 »

Вот вопрос. А вызов repaint из обработчика только paintEvent вызывает рекурсию? Или из любых обработчиков?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Октябрь 05, 2009, 13:24 »

Вот вопрос. А вызов repaint из обработчика только paintEvent вызывает рекурсию? Или из любых обработчиков?
"Только". Если в paintEvent вставить repaint, то он позовет тот же paintEvent - бесконечный рекурс (пока хватит стека). В др. обработчиках этого не произойдет. Также предполагается что метод paintEvent не порождает никаких событий, это плохо в любом случае.
Записан
Danila_Bagrofff
Гость
« Ответ #8 : Октябрь 05, 2009, 13:42 »

Вот вопрос. А вызов repaint из обработчика только paintEvent вызывает рекурсию? Или из любых обработчиков?
"Только". Если в paintEvent вставить repaint, то он позовет тот же paintEvent - бесконечный рекурс (пока хватит стека). В др. обработчиках этого не произойдет. Также предполагается что метод paintEvent не порождает никаких событий, это плохо в любом случае.

То есть все равно приходим к одному. Лучше исользовать update(). И проталкивать событие через processEvents?

Получается так? Если хотим все-таки увидеть перерисованную область =)

И еще, вызов update не вызывает рекурсию при вызове даже из eventPaint, Верно? потому как все равно встанет в очередь, и уже потом соединится с какими-то другими перерисовками и будет обработано в порядке очереди. Тое есть вызов update() безопасен из любого места программы?
« Последнее редактирование: Октябрь 05, 2009, 13:46 от Danila_Bagrofff » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Октябрь 05, 2009, 14:39 »

То есть все равно приходим к одному. Лучше исользовать update(). И проталкивать событие через processEvents?

Получается так? Если хотим все-таки увидеть перерисованную область =)

И еще, вызов update не вызывает рекурсию при вызове даже из eventPaint, Верно? потому как все равно встанет в очередь, и уже потом соединится с какими-то другими перерисовками и будет обработано в порядке очереди. Тое есть вызов update() безопасен из любого места программы?
Вот типичный пример когда нужен processEvents (вторичный цикл событий)

Программа что-то интенсивно считает. События накапливаются в очереди, но поскольку программа занята расчетом, никто их оттуда не извлекает и не обрабатывает, все "заморожено" для пользователя. Таймер здесь не поможет - это тоже событие. В этом случае показывают окно с бегунком (индикатором) и кнопкой "cancel". В вычислениях функция которая периодически продвигает бегунок, вызывает processEvents и затем проверяет была ли нажата "cancel". Это гарантирует что индикатор будет перерисован и "cancel" будет пойман.

Теперь смотрите сами это Ваш случай или нет. Если у Вас глухие расчеты - то да. Если же Вы что-то делаете с UI - то нет. Во-первых, processEvents может и не убрать задержку с рисованием, например если интенсивно создаются другие события которые опережают рисование. А главное - processEvents разрешит все др. события и будут вызваны их обработчики. А это может быть совсем не гуд пока Вы не закончили свои дела с UI. Поэтому если управление нужно держать - надо использовать repaint, а не processEvents

Ну вроде все (а то я расписАлся Улыбающийся)
Записан
Danila_Bagrofff
Гость
« Ответ #10 : Октябрь 05, 2009, 14:46 »

У нас не глухие расчеты, но выполнение методов set***  много. Много разных других потоков и есть обработчики событий, но не eventPaint. И зачастую бывает, что уже произошла установка set***, а отображения на экране нет. А нужно вовремя это делать.

Вот какой метод выбрать - это вопрос. В принципе, можно и repaint(). Но большое количество вызовов - вызовет мерцание, насколько я понимаю. А update тогда - толково вызывать только при вызове processEvents. Иначе неясно, когда же все обновится.

Наверно, стоит отдать предпочтение update().
Записан
Danila_Bagrofff
Гость
« Ответ #11 : Октябрь 07, 2009, 08:51 »

Созрел еще вопрос.

У меня происходит обработка какого-то пользовательского события в event(). Обрабатывая событие у меня изменяется состояние пользовательского интерфейса. Но мне нужно его вовремя обновить. Я, конечно, могу сделать запрос update(). Но он встанет в очередь.
Получается вызов QApplication::processEvents() отсюда делать нельзя? Потому как это вызов обработки событий из самого обработчика?
НАсколько это корректно?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Октябрь 07, 2009, 12:01 »

Созрел еще вопрос.

У меня происходит обработка какого-то пользовательского события в event(). Обрабатывая событие у меня изменяется состояние пользовательского интерфейса. Но мне нужно его вовремя обновить. Я, конечно, могу сделать запрос update(). Но он встанет в очередь.
Получается вызов QApplication::processEvents() отсюда делать нельзя? Потому как это вызов обработки событий из самого обработчика?
НАсколько это корректно?
Если используете processEvents - Вы должны быть уверены что все обработчики (которые processEvents позовет) не будут конфликтовать с кодом/обработчиком из которого processEvents вызван. Это удается обеспечить далеко не всегда. Если (как я понял) у Вас проблема с отрисовкой то решайте через repaint, стандартный прием - прицепить к нему clock. Псевдокод

Код:
void Repaint2( QWidget * w )
{
  static clock_t theLastClock = 0;
  clock_t curClock =  clock() / CLOCKS_PER_SEC;

  if (curClock - theLastClock > 30)  {                       

 // прошло полсекунды, рисуем
   w->repaint();
   theLastClock = clock() / CLOCKS_PER_SEC;  // запомним время после рисования
  }
  else {
// нечего на каждый чих repaint делать
  }
}
Ну и вставляйте Repaint2 в нужные места
Записан
Danila_Bagrofff
Гость
« Ответ #13 : Декабрь 10, 2009, 15:36 »

Еще вопрос.

Есть обработчик пользовательских событий в главном окне:
Код:
MainWindow::customEvent(QEvent *event)
{
 ...
myWidget->update();
}
В нем происходит обработка данных.

Есть мой виджет со своим обрабочиком событий перерисовки:
Код:
QMyWidget::paintEvent()
{
...
}

В принципе нужно что-то изменять на интерфейсе. Есть мой графический элемент QMyWidget *myWidget. Можем ли мы для него вызвать в обработчике событий главного окна метод update()?

В принципе, ничего не мешает встать новому событию в очередь событий и обработаться позже.

Правильно? Никаких логических ошибок нет?
« Последнее редактирование: Декабрь 10, 2009, 15:38 от Danila_Bagrofff » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Декабрь 10, 2009, 16:13 »

Правильно? Никаких логических ошибок нет?
Я лично не вижу:) Многие обработчики зовут update() и это нормально, нельзя только делать это из paintEvent
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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