Перейти к содержанию
    

Обновление GUI через таймер

Все привет!

 

Очередной вопрос, связанный с Visual Studio и языком C++, в частности.

 

На форме имеется статусбар. В нем несколько полей, которые обновляются в одном таймере. Конструкция типа:

 

void CMain::OnTimer(UINT nIDEvent)
{
 Upd0(var0);
 Upd1(var1);
 Upd2(var2);
}

 

Где каждая функция обновления что-то вроде:

 

void CMain::Upd0(int var)
{
 CString _str;

 _str.Format(L"%d", var);

 status_bar.SetIcon(1, m_ico_ena);
 status_bar.SetSetText(_str, 1, NULL);
}

 

Т.е. обновляется текст и иконка.

 

При обновлении ПЕРВОГО поля (в функции Upd0) на форме это поле мерцает. При обновлении последующих полей мерцания нет. Хочется, что бы мерцания не было и в первом поле. Не могу понять, как это связано.

 

Использую MFC.

 

Спасибо.

 

:smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При обновлении ПЕРВОГО поля (в функции Upd0) на форме это поле мерцает. При обновлении последующих полей мерцания нет. Хочется, что бы мерцания не было и в первом поле. Не могу понять, как это связано.

Странный эффект. Если поле находится во власти класса типа CDialog, то попробуйте в конце каждой фунцкии Upd поставить UpdateData(FALSE).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странный эффект. Если поле находится во власти класса типа CDialog, то попробуйте в конце каждой фунцкии Upd поставить UpdateData(FALSE).

 

Спасибо за совет. Но, к сожалению, этот флаг не помог. Я пробовал и другие варианты включения/выключения обновления данных, в т.ч. и статусбара - но результата не добился.

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня два дилетантских вопроса (MFC я когда-то давно так и не освоил, а сейчас, по-видимому, уже поезд ушёл :-) )

- SetSetText() - это не опечатка, так и надо?

- не лучше ли делать setIcon(), setText() только тогда, когда что-то ДЕЙСТВИТЕЛЬНО поменялось?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Часто для убирания мерцания, достаточно запретить стирание перед рисованием. Ну и рисовать потом так, чтобы новая картинка полностью обновляла старую.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня два дилетантских вопроса (MFC я когда-то давно так и не освоил, а сейчас, по-видимому, уже поезд ушёл :-) )

- SetSetText() - это не опечатка, так и надо?

- не лучше ли делать setIcon(), setText() только тогда, когда что-то ДЕЙСТВИТЕЛЬНО поменялось?

SetSetText() - очепятка)

 

Отображаемые данные и так меняются примерно раз в секунду. Так что разницы нет(

И, на мой взгляд, проще со строго дискретным промежутком времени проверять флаги и по их состоянию обновлять ГУЙ.

 

Часто для убирания мерцания, достаточно запретить стирание перед рисованием. Ну и рисовать потом так, чтобы новая картинка полностью обновляла старую.

100% новая картинка не полностью будет обновлять старую (разная длина выводимых сообщений). Наверное, можно добить пробелами остающееся место, но это мне совсем не нравится, лучше уж дергать одно узкое поле в начале.

 

 

Штудировал интернеты и книжки различные - все равно не могу понять, какого черта мерцает только первое обновляемое поле?! :smile3046:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

100% новая картинка не полностью будет обновлять старую (разная длина выводимых сообщений). Наверное, можно добить пробелами остающееся место, но это мне совсем не нравится, лучше уж дергать одно узкое поле в начале.

Значит надо так формировать, чтобы 100%-но перекрывала старую.

Не знаю, что такое "добить пробелами остающееся место" и почему не нравится, но я не раз делал вывод строк текста через цикл TextOut() + 4шт. FillRect() от краёв текста до соответствующих границ клиентской области окна - работает нормально и быстро.

Если контрол содержит сложное изображение, а не просто текст, то можно отрисовку всю сделать на битовой плоскости в памяти, а потом - BitBlt(). Тоже без всяких стираний.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я бы добавил некую "атомарность" этой перерисовке.

Перед вызовом первого Upd0(var0); запрещаем перерисовку(перестаем обрабатывать WM_PAINT), делаем все изменения и отрисовываемся один раз.

Мне кажется что в ином случае постоянно будет что-то мерцать и подергиваться потому что ваши изменения не синхронизированы с развёрткой монитора(или точнее с внутренним механизмом DirectDraw или какая там подсистема в винде окошки рисует)...

 

Почитайте вот тоже https://msdn.microsoft.com/en-us/library/ms969905.aspx

Меня это наводит на мысли, что в кишках MFC

Вот это

status_bar.SetIcon(1, m_ico_ena);

status_bar.SetSetText(_str, 1, NULL);

реализовано без применения описанной техники двойной буферизации. Надо глубже копать либо применить какой-нибудь хак типа предложенного мной выше. Как это конкретно применить к MFC не знаю.

 

Кажется CWnd::LockWindowUpdate() очень похоже на правду.

https://msdn.microsoft.com/en-us/library/1x...ockwindowupdate

 

While window updates are locked, the system keeps track of the bounding rectangle of any drawing operations to device contexts associated with a locked window. When drawing is reenabled, this bounding rectangle is invalidated in the locked window and its child windows to force an eventual WM_PAINT message to update the screen. If no drawing has occurred while the window updates were locked, no area is invalidated.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я бы добавил некую "атомарность" этой перерисовке.

Перед вызовом первого Upd0(var0); запрещаем перерисовку(перестаем обрабатывать WM_PAINT), делаем все изменения и отрисовываемся один раз.

Мне кажется что в ином случае постоянно будет что-то мерцать и подергиваться потому что ваши изменения не синхронизированы с развёрткой монитора(или точнее с внутренним механизмом DirectDraw или какая там подсистема в винде окошки рисует)...

У вас в голове каша из разных понятий.

Обработка WM_PAINT, как и других виндовых сообщений, выполняется в одном GUI-потоке. Если WM_PAINT выбрано из очереди сообщений окна и обрабатывается (идёт отрисовка), то никакой другой обработки сообщений (данного окна) быть не может и ничего его прервать не может.

А развёртка монитора - это совсем другое. И никакая "атомарность" перерисовок бороться с ней не может. Да и развёртка монитора никак не может приводить к мерцаниям картинки. По определению. Она может приводить только к некоторым артефактам на динамических картинках.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...