创建自定义窗口大小调整功能

Posted

技术标签:

【中文标题】创建自定义窗口大小调整功能【英文标题】:Create custom window resize functionality 【发布时间】:2020-11-05 16:38:20 【问题描述】:

我正在尝试在不使用 WS_THICKFRAMEWS_BORDERWS_SIZEBOX 样式的情况下创建无边框、无标题和可调整大小。

我不想使用这些样式,因为它们会创建边框,但更重要的是,当我使用 SetWindowCompositionAttribute 函数在窗口后面启用丙烯酸模糊时,由于某种原因,模糊超出了窗口 @987654321 @。

我查看了this repo,目前正在使用他们的命中测试逻辑。

所以基本上我认为我需要实现自己的调整大小的能力,但我不知道从哪里真正开始。

【问题讨论】:

在使用SetWindowCompositionAttribute(undocumented) 函数之前,希望你先阅读When programs grovel into undocumented structures…。无边框窗口可以参考the similar case。 谢谢,我会读的!我将重构以使用明显相似的记录在案的DwmSetWindowAttribute 函数。最初,由于我的风格标志,我在收听WM_NCHITTEST 时没有得到预期的行为。我现在已经解决了这个问题! @StriveSun-MSFT 如果可以的话,我会给这个评论两票。 【参考方案1】:

准确复制所有标准窗口大小调整行为有很多细微差别,但您需要做的主要事情是实现自己的 WM_NCHITTEST 处理程序,它基本上告诉 Windows 给定点位于窗口的哪个部分。

这是一个示例,它允许通过自定义标题栏区域进行拖动,并通过拖动窗口的左侧、右侧和底部来调整大小。

#include <windows.h>
#include <tuple>
#include "windowsx.h"

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)


    MSG msg =  0 ;
    WNDCLASS wc =  0 ;
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
    wc.lpszClassName = L"customwindowresizing";
    if (!RegisterClass(&wc))
        return 1;

    if (!CreateWindow(wc.lpszClassName,
        L"",
        WS_POPUP | WS_VISIBLE,
        0, 0, 640, 480, 0, 0, hInstance, NULL))
        return 2;

    while (GetMessage(&msg, NULL, 0, 0) > 0)
        DispatchMessage(&msg);

    return 0;


LRESULT HandleNonclientHitTest(HWND wnd, LPARAM lparam, int title_bar_hgt, int resizing_border_wd)

    RECT wnd_rect;
    GetWindowRect(wnd, &wnd_rect);

    int wd = wnd_rect.right - wnd_rect.left;
    int hgt = wnd_rect.bottom - wnd_rect.top;

    RECT title_bar =  0,0, wd, title_bar_hgt ;
    RECT left =  0, title_bar_hgt , resizing_border_wd , hgt - title_bar_hgt - resizing_border_wd ;
    RECT right = wd - resizing_border_wd , title_bar_hgt , wd, hgt - title_bar_hgt - resizing_border_wd ;
    RECT bottom =  0, hgt - resizing_border_wd, wd, hgt ;

    std::tuple<RECT, LRESULT> rects[] = 
        title_bar, HTCAPTION,
        left, HTLEFT,
        right, HTRIGHT,
        bottom, HTBOTTOM
    ;

    POINT pt =  GET_X_LPARAM(lparam) - wnd_rect.left, GET_Y_LPARAM(lparam) - wnd_rect.top ;
    for (const auto& [r, code] : rects) 
        if (PtInRect(&r, pt))
            return code;
    
    return HTCLIENT;


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)


    switch (message)
    
    case WM_CLOSE:
        PostQuitMessage(0);
        break;
    case WM_NCHITTEST:
        return HandleNonclientHitTest(hWnd, lParam, 25, 10);
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    
    return 0;


【讨论】:

【参考方案2】:

所以基本上我认为我需要实现自己的调整大小的能力

实际上,你没有。如果您只想通过窗口的右下角调整大小,只需在鼠标位于您认为是调整大小句柄的窗口区域时捕捉WM_NCHITTEST 并返回HTGROWBOX

WM_NCHITTEST 的其他更复杂的返回值是可能的(包括使用户可以在屏幕上拖动窗口),但你明白了。

【讨论】:

不幸的是,如果我在窗口样式中包含 WS_THICKFRAME 并且包含该标志会导致丙烯酸模糊模糊窗口,这似乎才有效 这让我很吃惊。我会仔细检查你的代码。如果操作正确,当您将鼠标悬停在调整大小手柄上时,您应该会看到光标变为调整大小箭头。此外,如果窗口设置了WS_CHILD,它可能不起作用。 你是对的,我的窗口样式冲突阻止了调整大小的行为

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

调整显示自定义字体大小的 MessageBox 窗口的大小?

使用窗口调整自定义视图的大小

使用自定义 QT 代码显示 QML 文件(实现调整大小/移动功能)

调整窗口大小时带有约束的宽度限制

使用媒体查询在调整窗口大小期间隐藏 div

wxWidgets源码分析 - 窗口尺寸