调整大小时创建自定义窗口边框边缘消失

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 我更新了代码,已经完成,应该可以编译了。 LOWORDHIWORD 不是检索打包到 LPARAM 中的鼠标指针坐标的正确方法。请改用GET_X_LPARAMGET_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 中的更新区域以仅绘制必要的部分。虽然在调整窗口大小时总会有一点滞后,即使使用常规窗口也可以注意到这一点。你对此无能为力。

以上是关于调整大小时创建自定义窗口边框边缘消失的主要内容,如果未能解决你的问题,请参考以下文章

调整大小时,使用虚线边框使窗口透明

当鼠标悬停在边框上时,如何完全禁用调整窗口大小,包括调整大小图标?

添加属性 QtCore.Qt.FramelessWindowHint 后如何从边缘调整窗口大小

VC/MFC 无边框鼠标拉伸改变窗口大小

易语言利用窗口消息实现无边框调整和移动窗口

Python OpenCV - 如何删除窗口边框和标题