C++ 是什么导致两个相等的后续SetWindowPos()调用设置不同的窗口大小?
作为我正在进行的项目的一部分,我想突出显示桌面的各个区域。现在我使用一个半透明的红色顶层窗口来实现这一点,即C++ 是什么导致两个相等的后续SetWindowPos()调用设置不同的窗口大小?,c++,winapi,C++,Winapi,作为我正在进行的项目的一部分,我想突出显示桌面的各个区域。现在我使用一个半透明的红色顶层窗口来实现这一点,即 使用红色背景笔刷创建自定义窗口类 为我的自定义类创建一个窗口,该窗口具有WS\u EX\u LAYERED样式集 调用以使窗口50%半透明 它基本上工作得很好,但我注意到覆盖窗口和函数之间有一个相当奇特的交互:当将宽度或高度传递给SetWindowPos时,它们分别小于32。39像素,第一次调用SetWindowPos实际上会使窗口比请求的窗口大,但后续调用会按预期工作。下面是一个小示例
WS\u EX\u LAYERED
样式集SetWindowPos
时,它们分别小于32。39像素,第一次调用SetWindowPos
实际上会使窗口比请求的窗口大,但后续调用会按预期工作。下面是一个小示例程序,它演示了这个问题-它在桌面的左上角创建覆盖窗口,然后以1秒的延迟调用两次SetWindowPos
。请注意,红色矩形首先是方形,然后垂直收缩
#include <windows.h>
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
// Register custom class for overlay window, forcing red background
WNDCLASSW overlayClassDef = {
0,
DefWindowProcW,
0,
0,
hInstance,
NULL,
NULL,
::CreateSolidBrush( RGB( 255, 0, 0 ) ),
NULL,
L"Overlay_Window"
};
ATOM overlayClass = ::RegisterClassW( &overlayClassDef );
// Create overlay window using 'layered' flag to enable making it
// translucent
HWND m_overlay = ::CreateWindowExW(
WS_EX_LAYERED | WS_EX_NOACTIVATE,
(LPCWSTR)overlayClass,
NULL,
0,
0,
0,
0,
0,
NULL,
NULL,
hInstance,
NULL
);
// Strip WS_BORDER and WS_DLGFRAME styles to get perfectly flat window; these
// styles appear to get added by default for toplevel windows.
int windowStyle = ::GetWindowLongPtr( m_overlay, GWL_STYLE );
windowStyle &= ~WS_BORDER;
windowStyle &= ~WS_DLGFRAME;
::SetWindowLongPtr( m_overlay, GWL_STYLE, windowStyle );
// Show the window and make it 50% translucent
::ShowWindow( m_overlay, SW_SHOWNA );
::SetLayeredWindowAttributes( m_overlay, 0, 127, LWA_ALPHA );
// Set the position to 100/100 (50x20 pixels); the window on
// screen becomes higher than 20 pixels though!
::SetWindowPos( m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE);
::Sleep( 1000 );
// Set the position once more -- this time, the window shrinks
// to 20 pixels vertically.
::SetWindowPos( m_overlay, HWND_TOPMOST, 100, 100, 50, 20, SWP_NOACTIVATE);
::Sleep( 1000 );
// Releasing resources omitted for brevity
return 0;
}
#包括
int WINAPI WinMain(HINSTANCE HINSTANCE、HINSTANCE HPPreInstance、LPSTR lpCmdLine、int nCmdShow)
{
//为覆盖窗口注册自定义类,强制使用红色背景
WNDCLASSW OVERYCLASSDEF={
0,
除窗程序,
0,
0,
hInstance,
无效的
无效的
::CreateSolidBrush(RGB(255,0,0)),
无效的
L“叠加窗口”
};
ATOM OverlyClass=::RegisterClassW(&OverlyClassDef);
//使用“分层”标志创建覆盖窗口,使其能够
//半透明的
HWND m_overlay=::CreateWindowExW(
WS_EX_分层| WS_EX_未激活,
(LPCWSTR)超循环类,
无效的
0,
0,
0,
0,
0,
无效的
无效的
hInstance,
无效的
);
//剥离WS_边框和WS_DLGFRAME样式,以获得完全平坦的窗口;这些
//默认情况下,顶级窗口会添加样式。
int windowStyle=::GetWindowLongPtr(m_覆盖,GWL_样式);
windowStyle&=~WS\u边框;
windowStyle&=~WS\u DLGFRAME;
::SetWindowLongPtr(m_叠加、GWL_样式、WindowsStyle);
//显示窗口并使其50%半透明
::显示窗口(m_叠加,SW_显示);
::SetLayeredWindowAttributes(m_overlay,0,127,LWA_ALPHA);
//将位置设置为100/100(50x20像素);打开窗口
//屏幕变得高于20像素!
::设置窗口位置(m_覆盖,HWND_最顶部,100,100,50,20,SWP_未激活);
::睡眠(1000);
//再次设置位置--这一次,窗口缩小
//垂直方向为20像素。
::设置窗口位置(m_覆盖,HWND_最顶部,100,100,50,20,SWP_未激活);
::睡眠(1000);
//为了简洁起见,省略了释放资源
返回0;
}
关于这种行为的一些观察:
WS_BORDER
或WS_DLGFRAME
,则不会出现此效果;不过,我想清除这两个标志,以获得一个完全平坦的窗口静态类
时,也可以复制此属性是否有一个接近32像素的魔法最小窗口大小需要特别处理?更新窗口样式后,您需要确保重新计算窗口大小和帧度量。为此,您需要在更新视觉样式后立即使用
SWP\u FRAMECHANGED
标志手动调用SetWindowPos
:
::SetWindowLongPtr( m_overlay, GWL_STYLE, windowStyle );
::SetWindowPos(m_overlay, NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOREDRAW);
如果为
dwStyle
传递了0
,则出现CreateWindow
指定默认窗口样式;在此处传递WS\u弹出窗口
可以避免触发奇怪的SetWindowPos
行为,还可以减少清除WS\u边框
和WS\u DLGFRAME
的需要。WS\u重叠
被定义为0x0
。“重叠窗口有一个标题栏和一个边框。”这可能解释了你的部分观察结果。@IInspectable啊,这很有趣-这让我想知道WS\u overlapped
是否适合在我的案例中使用。。也许我应该选择WS\u POPUP
?WS\u POPUP
看起来确实是个更好的选择。毕竟,您不需要标题栏或边框,只需要一个窗口,它只包含一个客户端区域。这看起来不错!值得一提的是,文档中指出,SWP\u NOOWNERZORDER
和SWP\u NOREPOSITION
是同义词,因此可以删除其中一个。支持这是正确答案的进一步证据:文档在备注部分中说明:“某些窗口数据是缓存的,因此在调用SetWindowPos函数之前,您使用SetWindowLong所做的更改不会生效。具体来说,如果更改任何帧样式,必须使用SWP_FRAMECHANGED标志调用SetWindowPos,才能正确更新缓存。”