调整大小时创建自定义窗口边框边缘消失
Posted
技术标签:
【中文标题】调整大小时创建自定义窗口边框边缘消失【英文标题】:Creating custom windows border edge disapears when resize smaller 【发布时间】:2017-04-26 00:02:50 【问题描述】:和标题说的差不多。
我正在尝试制作自己的边框,就像 Visual Studio 2015 那样。 一旦我的边框正常工作,我将添加一个子窗口,它是我的程序的主窗口,边框将是父窗口。 一旦我开始工作,我也会尝试添加外发光。
但我现在遇到的问题是,当我拖动边框以调整其大小以使其更小时,右侧或底部开始变薄,具体取决于我拖动鼠标的速度。
有没有更好的方法来做到这一点,或者我可以采取一个简单的步骤来解决它。
#include <windows.h>
LPTSTR className_ = TEXT("BorderWindow");
BOOL WINAPI Init(HINSTANCE hInstance, INT cmdShow);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, INT nCmdShow)
MSG msg;
if (!Init(hInstance, nCmdShow))
return FALSE;
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return (INT)msg.wParam;
BOOL WINAPI Init(HINSTANCE hInstance, INT cmdShow)
WNDCLASSEX wcex 0 ;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = 0;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_HIGHLIGHT + 1);
wcex.lpszClassName = className_;
wcex.hIconSm = NULL;
if (!RegisterClassEx(&wcex))
return FALSE;
HWND hwnd_ = CreateWindow(className_, className_, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 200, 500, nullptr, nullptr, hInstance, nullptr);
if (!hwnd_)
return FALSE;
ShowWindow(hwnd_, cmdShow);
UpdateWindow(hwnd_);
return TRUE;
void CreateHole(HWND hWnd)
HRGN WindowRgn;
HRGN HoleRgn;
//Get the window region:
RECT windowrect;
GetWindowRect(hWnd, &windowrect);
int width = windowrect.right - windowrect.left;
int height = windowrect.bottom - windowrect.top;
WindowRgn = CreateRectRgn(0, 0, width, height);
//Create the hole region:
HoleRgn = CreateRectRgn(2, 2, width - 2, height - 2);
CombineRgn(WindowRgn, WindowRgn, HoleRgn, RGN_DIFF);
SetWindowRgn(hWnd, WindowRgn, TRUE);
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
switch (message)
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_SIZE:
CreateHole(hwnd);
return 0;
case WM_NCCALCSIZE:
// remove default borders
return 0;
case WM_NCHITTEST:
RECT rc;
GetClientRect(hwnd, &rc);
POINT pt = LOWORD(lparam), HIWORD(lparam) ;
ScreenToClient(hwnd, &pt);
if (pt.y > (rc.bottom - 5))
if (pt.x > (rc.right - 5))
return HTBOTTOMRIGHT;
return HTBORDER;
return DefWindowProc(hwnd, message, wparam, lparam);
【问题讨论】:
我们可以看到minimal reproducible example 代替您的部分BorderWindow
实现吗?强烈建议删除任何抽象。
@IInspectable 我更新了代码,已经完成,应该可以编译了。
LOWORD
和 HIWORD
不是检索打包到 LPARAM
中的鼠标指针坐标的正确方法。请改用GET_X_LPARAM
和GET_Y_LPARAM
。
我可以使用 OPs 代码重现该问题。不太确定为什么会发生这种情况,但 AFAIK 窗口区域不能很好地与 DWM 配合使用。您需要不规则形状的框架还是矩形就足够了?
@zett42 我只需要一个矩形边框来环绕它的子窗口
【参考方案1】:
如果你只需要矩形框,可以实现如下更简单的解决方案:
窗口样式应该是正常情况下会显示整个框架(WS_CAPTION|WS_POPUP
适合我)。
拨打DwmExtendFrameIntoClientArea()
和MARGINS0,0,0,1
。
致电SetWindowPos(nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)
重新计算NC面积。
如果 wParam 是 TRUE
,则从 WM_NCCALCSIZE
返回 0。这具有将客户区扩展到包括框架在内的窗口大小的效果。常规窗框将被移除,但 DWM 仍会绘制阴影(另见WM_NCCALCSIZE 的备注部分)。
在WM_PAINT
中随意绘制框架和内容区域,但请确保为DwmExtendFrameIntoClientArea()
调用定义的边距设置不透明的Alpha 通道。否则,该区域将可见部分常规框架。您可以为此使用 GDI+,因为大多数常规 GDI 函数都会忽略 Alpha 通道。
您可以像往常一样将子控件放入此窗口。只要确保子控件不与DwmExtendFrameIntoClientArea()
调用定义的边距重叠,因为大多数 GDI 控件忽略 alpha 通道。
【讨论】:
WM_Paint 中绘制的边框/框架是否会在调整窗口大小的边缘消失? @vusuzireru 在WM_SIZE
中调用InvalidateRgn()
以将框架添加到更新区域。如果框架绘制仍然滞后太多,请将调用替换为RedrawWindow()
。确保检查WM_PAINT
中的更新区域以仅绘制必要的部分。虽然在调整窗口大小时总会有一点滞后,即使使用常规窗口也可以注意到这一点。你对此无能为力。以上是关于调整大小时创建自定义窗口边框边缘消失的主要内容,如果未能解决你的问题,请参考以下文章
当鼠标悬停在边框上时,如何完全禁用调整窗口大小,包括调整大小图标?