我正在使用Direct3D和WinAPI开发3D编辑器应用程序。我创建一个主窗口,其中有一个子窗口,该子窗口占据了主窗口客户区的一部分。 D3D将其用作渲染目标。然后,我还使用CreateWindow
创建一个单独的窗口,该窗口的构建方式与主窗口相同(即,“主窗口”和用作渲染目标的内部子窗口),并将该窗口作为子窗口。主应用程序窗口(以确保将它们最小化/还原/一起关闭)。
D3D渲染由渲染目标子窗口处理其WM_PAINT
消息来执行。为了减少不必要的开销,我将窗口过程设置为仅在WM_PAINT
和GetForegroundWindow
与相应的窗口句柄匹配时在GetFocus
上呈现。换句话说,我只希望刷新位于顶部且聚焦的窗口渲染。
这是我的主要消息循环:
HWND mainWnd;
HWND mainRenderWnd;
HWND childWnd;
HWND childRenderWnd;
// ...
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg,nullptr,PM_REMOVE))
{
if (!Translateaccelerator(mainWnd,accel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// Run non-UI code...
}
}
当主窗口获得WM_setfOCUS
时,我将焦点设置为其渲染目标子窗口,因为我要在那里处理输入(例如相机控件):
// ...
LRESULT CALLBACK MainWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
//...
case WM_setfOCUS:
{
setfocus(mainRenderWnd);
return 0;
}
//...
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
我在childWnd
的窗口过程中执行相同的操作,将焦点设置为childRenderWnd
。该窗口由用户打开和关闭,即在任何时候它可能存在或可能不存在,但是当它存在并且没有最小化时,它必须是具有焦点的前景窗口。另外,为了控制子窗口的帧率,我使用计时器刷新它:
static constexpr UINT_PTR RENDER_TIMER_ID = (UINT_PTR)0x200;
void TimerCallback(HWND Arg1,UINT Arg2,UINT_PTR Arg3,DWORD Arg4)
{
if (IsIconic(childWnd) || !(GetFocus() == childRenderWnd))
return;
// Invalidate the render area to make sure it gets redrawn
InvalidateRect(childRenderWnd,false);
}
// ...
SetTimer(childWnd,RENDER_TIMER_ID,16,(TIMERPROC)TimerCallback);
完成所有这些设置后,mainWnd
和mainRenderWnd
似乎工作正常。但是,childRenderWnd
处于前景和焦点时,拒绝渲染任何内容。在调试时,我发现虽然是这种情况,但计时器回调从未执行,也没有WM_TIMER
消息被调度到子窗口。
另一方面,当我故意将焦点移出子窗口并移至主窗口(同时保持打开状态)时,将发送计时器消息,并执行回调。另一个问题是,当我在两个窗口都打开时最小化应用程序,然后又将它们都还原时,两个窗口的渲染目标都不会刷新。取而代之的是,焦点似乎“翻转了”,因为我必须先单击子窗口,然后单击主窗口,然后才能正确刷新(而子窗口仍然拒绝渲染任何东西)。
我想念什么?我搜索了其他有问题的消息,例如错误的消息泵设置阻止了WM_TIMER
,但是似乎什么也无法解释这里的情况。
预先感谢您的帮助!