我有一个用WS_EX_LAYERED
窗口样式创建的窗口。我目前正在使用 GDI+ 绘制到内存位图上,并使用UpdateLayeredWindow
更新分层窗口的图形内容。我打算将此窗口用作应用程序的主窗口,这将需要它经常重绘。
看到分层窗口没有收到WM_PAINT
窗口消息[?],我需要想出一个合适的方法来重新绘制窗口。优化不是必需的,但吃蛋糕总是很高兴的。因此,我正在寻找要使用的"正确"方法。
以下是我到目前为止的想法:
-
我猜在
BitBlt
或类似之前渲染到屏幕外位图是个好主意。 -
每秒渲染 60 帧应该足够(超过?(了(但这与其他应用程序的帧速率相比如何?(。
可能的解决方案:
-
使用
SetTimer
定期发送WM_TIMER
消息。-
很有用,因为通过指定超时值,我可以达到每秒所需的帧数,而无需测量渲染"帧"所需的持续时间。
-
由于消息的频率和速度,可能会导致输入或其他滞后。
-
-
仅在发生特定事件(如窗口大小调整(时渲染帧。
- 需要
我弄清楚所有需要重绘的事件。
将大大减少渲染的不必要帧的数量。
-
当消息队列中没有消息时,通过选中
PeekMessage
来渲染帧。-
这可能会减慢窗口消息的处理速度。
-
这将导致高 CPU 使用率,因为正在处理的帧数超过了必要的帧数。
-
-
创建一个新线程来执行渲染循环。
- 必须执行时序计算以保持稳定的帧速率。
分层窗口不会接收WM_PAINT
消息,否则这些消息会在窗口可见性更改后生成,但它根本不会阻止它们接收此消息。
您可以继续使用 InvalidateRect
更改窗口更新区域,等待窗口中的WM_PAINT
过程,在位图中绘制内容并调用 UpdateLayeredWindow
来更改窗口内容。可以使用此方法在窗口内容更改时请求重绘,例如,按下按钮或调整窗口大小(或激活/停用(时。
它不应该那么复杂,这是你的消息循环的伪代码:
while (true)
{
// GetMessages
while (PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE))
{
if (!GetMessage(&msg, hWnd, 0, 0 ))
{
// Need to handle WM_QUIT
...
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
// Check if we need to draw
if (TimeForANewFrameHasCome() ||
IfWeNeedToDrawAfterInputOrInvalidate() ||
AnyOtherCaseThatCausesAnUpdate())
{
// Render
UpdateMemoryDCOrBitmap(...);
// Display it
UpdateLayeredWindow(...);
}
// May sleep a while
// Either Sleep(20); or better MsgWaitForMultipleObjects, that makes it possible
// to wake up upon an Event too...
MsgWaitForMultipleObjects(...);
}