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

时间:2017-04-26 00:02:51

标签: c++ winapi

这就是标题所说的内容。

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

1 个答案:

答案 0 :(得分:0)

如果您只需要矩形框架,可以通过以下方式实现更简单的解决方案:

  • 窗口样式应该通常显示整个框架(WS_CAPTION|WS_POPUP对我来说效果很好。)
  • 使用DwmExtendFrameIntoClientArea()致电MARGINS{0,0,0,1}
  • 致电SetWindowPos(nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)重新计算NC区域。
  • 如果wParam为WM_NCCALCSIZE,则从TRUE返回0。这具有将客户区扩展到包括帧的窗口大小的效果。将移除常规窗口框架,但DWM仍将绘制阴影(另请参阅WM_NCCALCSIZE的备注部分)。
  • WM_PAINT中根据需要绘制框架和内容区域,但请确保为DwmExtendFrameIntoClientArea()调用定义的边距设置不透明的Alpha通道。否则,在该区域中可以看到常规帧的一部分。您可以使用GDI +,因为大多数常规GDI函数都忽略alpha通道。

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