2016-12-02 1 views
-2

Я новичок в Win32 и с трудом получаю окно, чтобы перерисовать себя, когда захочу. Я подозреваю, что это имеет какое-то отношение к тому, что я пытаюсь использовать InvalidateRect (hWnd, NULL, FALSE); UpdateWindow (hWnd);Вызов UpdateWindow извне WM_PAINT в Win32?

в функции CALLBACK WndProc WM_COMMAND, то есть вне WM_PAINT. В этом случае окно не будет обновляться сразу и что вместо этого он будет накапливать все вызовы перерисовки и ждать «позже», когда вызывается WM_PAINT?

Спасибо!

+0

С вашей нынешней формулировкой вы привлекаете только тех, кто знает подкраски и порядок наизусть. Если вы хотите, чтобы у других была попытка попробовать, вы можете прочитать [ask] и предоставить [mcve], который, я думаю, возможен в строке или 10 кода. – CodeCaster

+0

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

+0

@DavidHeffernan: [UpdateWindow] (https://msdn.microsoft.com/en-us/library/dd145167.aspx) * «[...] отправляет сообщение WM_PAINT непосредственно в оконную процедуру указанного окна, * * в обход очереди приложений **. * – IInspectable

ответ

2

Возможно ли, что окно не будет обновляться сразу и что оно вместо этого будет накапливать все вызовы перерисовки и ждать «позже», когда вызывается WM_PAINT?

Нет, это не кейс.

Что вы описали, в основном, как работает , и вот что произойдет, если вы просто позвонили InvalidateRect. Клиентская область окна была бы просто отмечена как «недействительная», и сообщение WM_PAINT было бы отправлено, если в очереди не будет сообщений, ожидающих обработки очереди. Единственное, что ваше описание ошибочно, заключается в том, что призывы рисования/перерисовки не «накапливаются». Если вы позвоните по номеру InvalidateRect 20 раз, вы получите сообщение только 1 WM_PAINT. Идея этой «ленивой» стратегии живописи заключается в том, что живопись - это низкоприоритетная, но дорогостоящая операция, и эта «нетерпеливая» живопись приведет к кучке потраченных впустую циклов - вы можете нарисовать что-то, что только будет перекрашено через несколько микросекунд позже.

Но тот факт, что вы позвонили UpdateWindow, меняет все это. Эта инструкция заставляет перерисовать сразу. Как the documentation говорит:

Функция UpdateWindow обновляет клиентскую область указанного окна, отправив сообщение WM_PAINT к окну, если область обновления окна не является пустым. Функция отправляет сообщение WM_PAINT непосредственно в оконную процедуру указанного окна, минуя очередь приложения. Если область обновления пуста, сообщение не отправляется.

Первоначальный звонок в InvalidateRect помечен как клиентская область окна как недействительный, создавая непустую область обновления для окна. Последующий вызов UpdateWindow заметил, что это окно нуждается в перекраске, и принудительно перерисовал сразу, отправив процедуру окна сообщение WM_PAINT напрямую, минуя обычную очередь сообщений.

Как правило, нет причин для звонка UpdateWindow. Пусть диспетчер окон обрабатывает отправку писем, когда он определяет, что это подходящее время для перерисовки. Единственный раз, когда вам понадобится позвонить UpdateWindow, - это если вы делаете что-то вроде дорогостоящего вычисления в ответ на другое сообщение. Это блокирует поток пользовательского интерфейса, не обрабатывая любые другие сообщения, включая сообщения WM_PAINT. Это плохой вещь по многим причинам. Один из них заключается в том, что он не позволяет вашему окну перекрашиваться.Еще одна серьезная проблема заключается в том, что это приводит к тому, что ваше приложение перестает отвечать на запросы пользователей, поскольку оно перестает отвечать на входные сообщения. Если вам нужно сделать некоторые трудоемкие вычисления, сделайте это на фоновом потоке.

Но там есть несколько случаев, когда вы можете позвонить по номеру UpdateWindow. Я использовал его несколько раз, и он работает точно так, как описано выше. Я понятия не имею, почему у вас возникают проблемы с его работой; вы забыли включить образец кода, который воспроизводит проблему в вашем вопросе.

это не похоже, чтобы сделать это, когда я ставлю InvalidateRect затем UpdateWindow внутри WM_COMMAND

Это абсолютно не важно, что это делается в обработчике WM_COMMAND сообщения. Вы можете делать это где угодно. Важно то, что вы сначала заставляете часть клиентской области окна стать недействительной (что вы делаете с InvalidateRect), а затем принудительно перерисовываете перерисовку этой недопустимой области (которую вы выполняете с UpdateWindow).

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

+0

Хорошо спасибо за педагогический ответ, я добираюсь туда сейчас; это так же, как вы сказали, что перерисовка сразу же вызвала. Я не публиковал исходный код, потому что он длинный, и я понял, что это что-то основное, что и было. – Johan

+3

Основным правилом здесь в Stack Overflow является публикация [MCVE], которая демонстрирует проблему, с которой вы сталкиваетесь.Разумеется, верно, что для создания такого примера требуется работа, и также верно, что процесс генерации этого примера часто приводит к тому, что вы сами выясняете проблему. Это все по дизайну. :-) Но на самом деле, это единственный способ помочь вам. Единственная альтернатива - это долгий, бесстрашный ответ, который пытается научить вас всему, что касается конкретного API, который большинство людей не займет время, чтобы писать, и редко очень полезно для решения конкретной проблемы. @joh –

-1

В случае, если у кого-то другого новичка есть подобные проблемы, может быть полезно поставить Sleep (2000) перед вашим InvalidateRect вместе со строковым выводом о том, где вы сейчас находитесь, таким образом вы не будете сомневаться в том, что произойдет, когда. По крайней мере, так я нашел свою проблему ...

+1

В значительной степени * последняя * вещь, которую вы должны делать при отладке приложений пользовательского интерфейса, и особенно проблем с окраской, - это вставки вызовов 'Sleep'. Функция полезна только в очень изолированных необычных ситуациях, но новички-программисты склонны ее злоупотреблять. Это гораздо более вероятно, что вы поедете, чем помочь. Я предполагаю, что довольно неплохо поместить все, что вам нужно, в целях отладки, если вы удалите его и тщательно протестируете программу перед выпуском. Но все же «Сон» может часто приводить вас к недействительным или бессмысленным выводам. Я бы не рекомендовал его в качестве стратегии. –

+1

Что * делает * имеет смысл, однако, выводит какую-то информацию о состоянии/местоположении. Очевидно, что «MessageBox» не будет работать в коде UI, потому что это нарушает операции рисования. Но 'OutputDebugString' работает очень хорошо. Вы можете просмотреть этот вывод либо в выделенном средстве просмотра отладки, например в DebugView, либо непосредственно в Visual Studio, так как он перенаправляет этот вывод либо в окно вывода, либо в окно Immediate. * Чрезвычайно * удобно! –

+0

Хорошо, спасибо за помощь! – Johan

 Смежные вопросы

  • Нет связанных вопросов^_^