如何完全删除 window 的 non-client 区域?
How can I remove a window's non-client area completely?
我需要一个 window 没有标题栏、none 控制框、没有系统菜单和框架(所有这些功能都由单独的控件提供) .
我怀疑这可能与 CreateWindowExA
的 window 样式参数 dwStyle
和可能的 lpWindowName
有关,如下所述:https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-styles
参数原来是这样的:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_OVERLAPPEDWINDOW, // Window style.
// Size and position.
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
然而,在dwStyle
中,正常的window样式WS_OVERLAPPEDWINDOW
被定义为
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
WS_OVERLAPPED
为 0x00000000L
。
仅提供 0 并省略其余部分是行不通的,正如文档所暗示的那样:"The window is an overlapped window. An overlapped window has a title bar and a border."
(有趣的是,通过将 ControlBox
属性 设置为 VB.NET(甚至 VB6),我完全能够完成这项任务False
然后使用 Text = ""
删除标题栏,所以我强烈怀疑 VB...)
我将如何在 C++ 中完成我的任务?
以防万一需要 WindowProc
来处理不同的消息,这里是它的简约版本:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
(使用 VS 2017 编译。)
顶层的非客户区window可以通过仅使用WS_POPUP
风格来移除:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_POPUP, // Window style.
// Size and position.
100, 100, 400, 300,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
请注意,大小和位置的 CW_USEDEFAULT
仅对重叠的 windows 有效。对于弹出 windows 你必须明确。
根据您的用例,this answer 描述的技术可能更适合。使用 DWM API,它允许您删除非客户区,但 保留投影 以使 window 从背景中更好地脱颖而出。
我需要一个 window 没有标题栏、none 控制框、没有系统菜单和框架(所有这些功能都由单独的控件提供) .
我怀疑这可能与 CreateWindowExA
的 window 样式参数 dwStyle
和可能的 lpWindowName
有关,如下所述:https://docs.microsoft.com/en-us/windows/desktop/winmsg/window-styles
参数原来是这样的:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_OVERLAPPEDWINDOW, // Window style.
// Size and position.
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
然而,在dwStyle
中,正常的window样式WS_OVERLAPPEDWINDOW
被定义为
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
WS_OVERLAPPED
为 0x00000000L
。
仅提供 0 并省略其余部分是行不通的,正如文档所暗示的那样:"The window is an overlapped window. An overlapped window has a title bar and a border."
(有趣的是,通过将 ControlBox
属性 设置为 VB.NET(甚至 VB6),我完全能够完成这项任务False
然后使用 Text = ""
删除标题栏,所以我强烈怀疑 VB...)
我将如何在 C++ 中完成我的任务?
以防万一需要 WindowProc
来处理不同的消息,这里是它的简约版本:
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
(使用 VS 2017 编译。)
顶层的非客户区window可以通过仅使用WS_POPUP
风格来移除:
HWND hwnd = CreateWindowEx(
0, // Optional window styles.
CLASS_NAME, // Window class.
L"", // No window name (title text).
WS_POPUP, // Window style.
// Size and position.
100, 100, 400, 300,
NULL, // Parent window.
NULL, // Menu.
hInstance, // Instance handle.
NULL // Additional application data.
);
请注意,大小和位置的 CW_USEDEFAULT
仅对重叠的 windows 有效。对于弹出 windows 你必须明确。
根据您的用例,this answer 描述的技术可能更适合。使用 DWM API,它允许您删除非客户区,但 保留投影 以使 window 从背景中更好地脱颖而出。