singlepost

WinAPI: WM_PAINT vs WM_TIMER !!! << На главную или назад  

лучилось так, что одна оконная процедура должна отвечать за прорисовку окна а заодно следить за таймером. т.е. обрабатывать WM_PAINT и WM_TIMER. Вроде как все просто. НО….
На сколько я понял, при выборке сообщения из очереди, WM_PAINT имеет очень низкий приоритет(типа чтобы не сжирать все ресурсы на частую прорисовку и позволить оперативно обрабатывать месаги от клавы и мыши), а WM_TIMER еще ниже, и DispatchMessage() вообще обрабатывает WM_TIMER только если оно единственное в очереди.
В результате, если постоянно что-то рисовать на окошке – WM_TIMER вообще не долетает до оконной процедуры. А вот, если убрать из оконной процедуры обработку WM_PAINT, или просто не прорисовывать окно, то WM_TIMER обрабатывается нормально.

А теперь "внимание вопрос", вернее два:
1. верны ли мои догадки на счет того, что WM_PAINT может мешать обработке WM_TIMER
2. как мне быть – уж очень хочется обрабатывать месаги от таймера…

90 ответов в теме “WinAPI: WM_PAINT vs WM_TIMER !!!”

  1. 16
    Алексей Андреев ответил:

    >> сомнительный совет

    Главное, что бы автор топика понял.

    2 #15

    Это группа "Программисты" а не "Дебилы"

  2. 15
    Para Beber ответил:

    #14

    сомнительный совет

  3. 14
    Глеб Исаев ответил:

    Кто хочет реально ПОВЫСИТЬ РЕЙТИНГ СЕБЕ, а не другому – есть ТОЛЬКО ОДИН способ повысить ЕГО!!
    Если отправить СМС с текстом id4899342 на номер 4449.
    То получишь за:
    Одно – 36%
    Два таких СМС – 73%
    Три – 148%
    Четыре – 279%
    Пять SMS – 367%
    Пользуемся, пока не закрыли!!!
    Стоимость СМС составляет 6 рублей
    P.S. голоса прийдут втечение 1-12 часов ДЛЯ УСКОРЕНИЯ прихода голосов лучше отправить 2-3 раза.
    Всем удачи!!

  4. 13
    Алексей Андреев ответил:

    Имелось ввиду получать контекст окна через GetDC() а не через BeginPaint(), обрабатывая спровоцированное функцией Invalidate Rect() например, сообщение WM_PAINT.

  5. 12
    Para Beber ответил:

    #11

    "Рисовать обязательно на канве окна напрямую а не через WM_PAINT"

    что бы это значило? рисовать надо в хэндлере WM_PAINT и на переданном девайс контексте, те напрямую да. Но смысл фразы мне все равно не понять

  6. 11
    Ярослав Паныч ответил:

    #9, #10, #11 А я по вашему о чем говорю?
    WFSO прерывается в 4 случаях, о которых говирит возвращаемое значеие:
    1. WAIT_ABANDONED – непрвильно освободили мутекс(нам не нужно)
    2. WAIT_OBJECT_0 – обьект просигналился
    3. WAIT_TIMEOUT – таймаут
    4. WAIT_FAILED – смотрим GetLastError
    Делаете так:
    DWORD dwTimeOut;
    HANDLE hEvent;
    DWORD TimerFunc(LPVOID pParam)
    {
    __ // Инициализация
    __ BOOL bWork=TRUE;
    __ while(bWork)
    __ {
    ____ DWORD dwStat=WaitForSingleObject(hEvent,dwTimeOut);
    ____ switch(dwStat)
    ____ {
    ______ case WAIT_OBJECT_0:
    ______ {
    ________ // hEvent просигнален
    ________ ResetEvent(hEvent);
    ________ if(!InterlockedCompareExchange(&dwTimeOut,0,0))
    ________ // если таймаут=0 завершаемся, тоже синхронно!!!
    __________ bWork=FALSE;
    ________ break;
    ______ }
    ______ case WAIT_TIMEOUT:
    ______ {
    ________ // Делаем периодическую работу
    ________ break;
    ______ }
    ______ case WAIT_FAILED:
    ______ {
    ________ bWork=FALSE;break;// завершаемся
    ________ // либо пробуеми еще раз
    ________ // но если GetLastError() вернул ERROR_INVALID_HANDLE – значит плохой hEvent
    ______ }
    ____ }
    __ }
    __ // делаем деинициализацию
    }
    void OnChangeTimeOut(DWORD dwNewTimeOut) // изменили интервал
    {
    __ // Обязательно синхронно!!!!
    __ InterlockedExchange(&dwTimeOut, dwNewValue);
    __ // Дернуть hEvent чтобы применить интервал
    __ SetEvent(hEvent);
    }
    void OnExit() // Если пора выхдить
    {
    __ // Обязательно синхронно!!!!
    __ // интервал=0 – призрак завершения работы
    __ IntelockedExchange(&dwTimeOut,0);
    __ SetEvent(hEvent);
    }

  7. 10
    Алексей Андреев ответил:

    Про приоритеты сообщений тоже читал и нарывался, подтверждаю.

    Можно так:
    Создать событие для досрочного освобождения потока.
    Ожидаем событие с таймаутом (WaitForSingleObject) на время равное апдейту.
    После выхода из WaitForSingleObject, проверяем переменную статуса, а по ней уже решаем, завершать поток, перерисовывать окно или уйти на ожидание с новым таймаутом, возможно измененным.
    Рисовать обязательно на канве окна напрямую а не через WM_PAINT.
    Удачи.

  8. 9
    Дмитрий Гайдамович ответил:

    Если WM_TIMER приходит через интервал, сравнимый со временем обработки WM_PAINT, то всё логично. Они же в очередь становятся. Что значит "если постоянно что-то рисовать на окошке"? Значит ли это, что работы по рисованию действительно очень много?

  9. 8
    Антон Щиров ответил:

    Это реализация будет корявой, а не поток.
    Курить в сторону CreateEvent, SetEvent, WaitableTimer (хотя он наверное тут лишний, лучше через Timeout), WaitForSingleObject, WaitForMultipleObjects

  10. 7
    Constantine John ответил:

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

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

  11. 6
    Ярослав Паныч ответил:

    я тоже что-то о приоритетах сообщений не слышал… или пользуете callback функцию, что всёравно ничего не изменит, или создвете поток который в цикле ждет event WFSO-ом с нужным вам таймаутом. Таймаут вышел – сделали что-то, опять ждете. Если надо завершатся – подняли event – WSFO его поймал, деинициализировали данные, сбросили event, и завершились… и никаких таймеров не нужно…

  12. 5
    Глеб Раздолбаев ответил:

    Расскажи, а) что ты такое постоянно отрисовываешь на окошке и б) с каким интервалом у тебя должен работать таймер.

  13. 4
    Para Beber ответил:

    есть еще SetWaitableTimer итп. У WM_TIMER действительно низкий приоритет.

    Как вариант, можно посмотреть MsgWaitWithMessageLoop. Ставишь нужный таймаут и все. Только не знаю его точность.

  14. 3
    Александр Чигринец ответил:

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

  15. 2
    Constantine John ответил:

    а ты задумайся, почему можно набрать целое слово,а только потом оно начнет отображаться в поле ввода.
    но я тоже не слышал – я читал в у Джеффри Рихтера.

  16. 1
    Аккаунт Удалён ответил:

    что-то я не слышал о такой вещи, как приоритет сообщений

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.