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

标签 c++ winapi

几乎如标题所说。

我正在尝试制作自己的边框,就像 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);
}

最佳答案

如果只需要矩形边框,可以采用如下更简单的解决方案:

  • 窗口样式应该是这样的,通常整个框架都会显示(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 channel 。否则部分常规框架将在此区域可见。您可以为此使用 GDI+,因为大多数常规 GDI 函数会忽略 alpha channel 。

您可以像往常一样将子控件放入此窗口中。只需确保子控件不与 DwmExtendFrameIntoClientArea() 调用定义的边距重叠,因为大多数 GDI 控件会忽略 alpha channel 。

关于c++ - 创建自定义窗口边框边缘在调整大小时消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43622839/

相关文章:

c - 如何检测本地主机关闭的连接?

c - 如果我打算通过多个进程访问文件的多个部分,使用 CreateFileMapping 和 MapViewOfFile 的正确方法是什么?

winapi - WM_COPYDATA、PostThreadMessage 和错误 1159

c++ - 当.h和.cpp文件中的定义和声明分开时,getter和setter可以内联吗?

Python 安装编译错误

c++ - 派生自其实例以固定格式(数据库、MMF)驻留的基类……如何安全?

c++ - parallel_for/parallel_for_each 内部或外部的类对象?

C++ 运算符重载错误

Windows:作为服务运行时查找屏幕分辨率

c++ - 判断鼠标是否水平移动(C++)