[英]What might cause two equal subsequent SetWindowPos() calls to set different window sizes?
As part of a project I'm working on, I'd like to highlight regions of the desktop. 作为我正在进行的项目的一部分,我想突出显示桌面区域。 Right now I implement this using a translucent red top level window, ie I 现在,我使用半透明的红色顶级窗口来实现此功能,即
WS_EX_LAYERED
style set. 创建一个具有WS_EX_LAYERED
样式集的自定义类的窗口。 SetLayeredWindowAttributes
to make the window 50% translucent. 调用SetLayeredWindowAttributes
使窗口50%半透明。 It mostly works quite well, but I noticed a fairly peculiar interaction between my overlay window and the SetWindowPos
function: when passing widths or heights to SetWindowPos
which are smaller than 32 resp. 它通常工作得很好,但是我注意到覆盖窗口和SetWindowPos
函数之间存在相当特殊的交互作用:将宽度或高度传递给小于32的SetWindowPos
。 39 pixels, the first call to SetWindowPos
will actually make the window larger than requested but subsequent calls work as expected. 39像素,对SetWindowPos
的第一次调用实际上会使窗口大于请求的大小,但随后的调用按预期工作。 Here's a small sample program which demonstrates the issue - it creates the overlay window in the top left corner of the desktop and then calls SetWindowPos
twice with a one second delay. 这是一个演示该问题的小示例程序-它在桌面的左上角创建叠加窗口,然后以一秒钟的延迟两次调用SetWindowPos
。 Notice how the red rectangle is first about square and then shrinks vertically. 注意红色矩形如何首先围绕正方形,然后垂直缩小。
#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;
}
Some observations regarding this behaviour: 关于此行为的一些观察:
WS_BORDER
or WS_DLGFRAME
is set in the window flags; 如果在窗口标志中设置了WS_BORDER
或WS_DLGFRAME
则不会发生这种情况。 however, I'd like to clear both flags to get a perfectly flat window. 但是,我想同时清除这两个标志才能获得完美的平面窗口。 STATIC
class. 当不使用自定义窗口类而是实例化内置STATIC
类时,也可以重现此内容。 Is there maybe a magic minimum window size close to 32 pixels which has to be treated specially? 是否有可能需要特别对待的接近32像素的魔术最小窗口大小?
After you update window style you need to make sure that window size and frame metrics get recalculated. 更新窗口样式后,需要确保重新计算窗口大小和框架度量。 In order to do so you need to manually call SetWindowPos
with SWP_FRAMECHANGED
flag right after updating visual style: 为此,您需要在更新视觉样式后立即使用SWP_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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.