创建自定义窗口边框时,缩小窗口后边缘消失

3
基本上就是标题所说的。我正在尝试制作自己的边框,就像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);
}

我们能否看到一个[mcve],而不是你的部分BorderWindow实现?强烈建议删除任何抽象。 - IInspectable
@IInspectable 我更新了代码,它已经完成了,你应该能够构建它。 - vusuzireru
LOWORD和HIWORD不是正确的检索打包到LPARAM中的鼠标指针坐标的方法。请改用GET_X_LPARAM和GET_Y_LPARAM。 - Cody Gray
我可以使用 OP 的代码重现这个问题。不太确定为什么会发生这种情况,但据我所知,窗口区域与 DWM 不兼容。您需要不规则框架形状还是矩形就足够了? - zett42
@zett42 我只需要一个矩形边框来包裹它的子窗口。 - vusuzireru
1个回答

0
如果你只需要矩形框架,可以采用以下简单的解决方案:
  • 窗口样式应如平常所见,整个框架应该都显示出来(WS_CAPTION|WS_POPUP 对我来说很有效)。
  • MARGINS{0,0,0,1} 调用 DwmExtendFrameIntoClientArea()
  • 调用 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中检查更新区域,只绘制必要的部分。尽管调整窗口大小时总会有一些滞后,即使是普通窗口也可以注意到这一点。你无法做太多关于这个问题。 - zett42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接