退出全屏模式后清除屏幕?
我已经运行了一个 OpenGL 应用程序,可以在全屏模式和窗口模式之间切换。目前它通过调整窗口大小和更改样式来实现此目的。
然而,从全屏模式切换到窗口模式时,它似乎不会使屏幕失效,这使得我在切换后绘制的内容在屏幕上徘徊。 有趣的是,它仅在单显示器模式下表现出这种行为。如果我使用多个显示器运行,它会失效,并清除我的绘图。
我不认为这是一个驱动程序错误,因为它发生在使用两个独立显卡的两台独立计算机上(尽管不可否认它们都是 nVidia。),我认为我在某个地方做错了。
我尝试了多种方法让 Windows 清除之前全屏绘图的屏幕,但似乎没有任何效果。 InvalidateRect()、RedrawWindow()、ChangeDisplaySettings()... 具体来说:
InvalidateRect(m_hwnd, &rectx, true); // rect being the dimensions of either the screen or my window.
InvalidateRect(HWND_DESKTOP, NULL, TRUE); // Doesn't seem to do anything.
RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
ChangeDisplaySettings(NULL, 0);
嗯,实际上,在调整大小之前似乎确实有效的一件事是 ShowWindow(hwnd, SW_HIDE) 。然而,这会暂时失去焦点,允许其他应用程序获取我的应用程序的输入,这似乎是一个糟糕的方法。 我应该注意的是,当我看到这种行为时,我并没有进行任何实际的显示模式更改;只是保持当前的全屏分辨率。
我有点不知道我哪里错了。简化的代码:
if(m_isFullscreen)
{
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
else
{
ChangeDisplaySettings(&m_dmSavedScreenSettings, 0);
}
if(m_isFullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(false);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
if(m_isRunning) // Because ShowCursor uses a counter to indicate, and windowed mode defaults to cursor on, we don't need to increment the counter and double it being on.
{
ShowCursor(true);
}
}
RECT rect;
rect.left = 0;
rect.top = 0;
if(m_isFullscreen) { rect.right = 1280; } else { rect.right = 640; }
if(m_isFullscreen) { rect.bottom = 1024; } else { rect.bottom = 480; }
AdjustWindowRectEx(&rect, dwStyle, false, dwExStyle);
SetWindowLongPtr(m_hwnd, GWL_STYLE, dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, dwExStyle);
if(m_isFullscreen)
{
MoveWindow(m_hwnd, 0, 0, 1280, 1024, true);
}
else
{
MoveWindow(m_hwnd, 0, 0, 640, 480, true); // windowed
}
或多或少就是这样。其他一些支持代码和错误检查,但这就是我正在做的... dmSavedSettings 是在从 NULL 分配 m_hwnd 之前保存的,而不是之后保存的。我最初的窗口创建工作正常,全屏工作正常。它只是在全屏后返回到窗口,这就是问题所在。
So I've got an OpenGL application running that can toggle between fullscreen mode and windowed mode. It currently does this by resizing the window and changing styles.
However, it seems to not invalidate the screen when switching from fullscreen mode to windowed mode, which leaves things I've drawn lingering onscreen after the switch.
Interestingly, it only exhibits this behavior in single monitor mode. If I'm running with multiple monitors, it invalidates okay, and clears my drawing.
I don't think this is a driver bug, as it's happening on two separate computers using two separate video cards(although admittedly they are both nVidia.), I'm thinking I'm doing something wrong somewhere.
I've tried a bunch of methods for getting Windows to clear the screen of my previously fullscreen drawings, but nothing seems to work. InvalidateRect(), RedrawWindow(), ChangeDisplaySettings()...
Specifically:
InvalidateRect(m_hwnd, &rectx, true); // rect being the dimensions of either the screen or my window.
InvalidateRect(HWND_DESKTOP, NULL, TRUE); // Doesn't seem to do anything.
RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_UPDATENOW);
ChangeDisplaySettings(NULL, 0);
Well, actually, one thing that does seem to work is ShowWindow(hwnd, SW_HIDE) before resizing. However that loses focus for a moment, allowing other applications to grab my application's input, and seems a bad way to go about it.
I should note that I'm not doing any actual display mode changes when I'm seeing this behavior; just staying at the current resolution for fullscreen.
I'm a bit clueless where I'm going wrong. Simplified code:
if(m_isFullscreen)
{
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
}
else
{
ChangeDisplaySettings(&m_dmSavedScreenSettings, 0);
}
if(m_isFullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(false);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
if(m_isRunning) // Because ShowCursor uses a counter to indicate, and windowed mode defaults to cursor on, we don't need to increment the counter and double it being on.
{
ShowCursor(true);
}
}
RECT rect;
rect.left = 0;
rect.top = 0;
if(m_isFullscreen) { rect.right = 1280; } else { rect.right = 640; }
if(m_isFullscreen) { rect.bottom = 1024; } else { rect.bottom = 480; }
AdjustWindowRectEx(&rect, dwStyle, false, dwExStyle);
SetWindowLongPtr(m_hwnd, GWL_STYLE, dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
SetWindowLongPtr(m_hwnd, GWL_EXSTYLE, dwExStyle);
if(m_isFullscreen)
{
MoveWindow(m_hwnd, 0, 0, 1280, 1024, true);
}
else
{
MoveWindow(m_hwnd, 0, 0, 640, 480, true); // windowed
}
And that's more or less it. Some other supporting code and error checking, but that's what I'm doing... dmSavedSettings is saved before m_hwnd is assigned from NULL, and not afterwards. My initial window creation works fine, and fullscreen works fine. It's just returning to Windowed after being fullscreen that's the issue.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您在窗口类中设置空背景画笔,窗口将不会自动清除。您必须添加一个调用 OpenGL 显示处理程序的 WM_PAINT 处理程序,该处理程序又会清除视口 (glClearColor) 并重新绘制。
If you set a null background brush in your window class, windows will not be cleared automatically. You must add a WM_PAINT handler that calls your OpenGL display handler, which in turn clears the viewport (glClearColor) and redraws.
正如 datenwolf 在另一个答案的评论中提到的那样,在使用 SetWindowLongPtr() 时,您希望使用 SetWindowPos() 而不是 MoveWindow() 。
通过在调整窗口大小后调用 ChangeDisplaySettings(NULL, 0) 解决了我的脏背景问题。之前这样做效果不大,但之后似乎效果很好。
As datenwolf mentions in another answer's comment, you want to use SetWindowPos() instead of MoveWindow() when making use of SetWindowLongPtr().
My dirty background problems were solved by calling ChangeDisplaySettings(NULL, 0) AFTER resizing my window. Doing it before does little, but afterwards appears to work fine.