无法通过 SetScrollInfo 设置滚动条的范围

Roy Li - MSFT 32,646 信誉分 Microsoft 供应商
2024-05-17T01:44:34.41+00:00

我正在读佩佐尔德先生的书,试图做一个记事本。当插入符号到达工作区的最后一行并按 Enter 键时,我需要设置滚动条的范围(在 nMax 上加 1),但我发现如果我通过 SetScrollInfo 设置滚动条的范围,总是失败,范围永远不会改变,除非我在 SetScrollInfo 之前使用 ShowScrollBar。

 

以下是可以重现故障的最小代码:

#include <Windows.h>

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

int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR cmdLine, int cmdShow)
{
    PCWSTR szAppName = L"notepad";
    WNDCLASSEXW wndClass;

    ZeroMemory(&wndClass, sizeof(WNDCLASSEX));

    wndClass.cbSize = sizeof(WNDCLASSEX);
    wndClass.style = CS_HREDRAW | CS_VREDRAW;
    wndClass.cbClsExtra = 0;
    wndClass.cbWndExtra = 0;
    wndClass.lpfnWndProc = WndProc;
    wndClass.hInstance = hInstance;
    wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName = szAppName;
    wndClass.hIconSm = NULL;

    if (!RegisterClassExW(&wndClass))
    {
        MessageBoxW(NULL, L"Failed to register window class.", L"Message", 0);
        return 0;
    }

    HWND hWnd = CreateWindowExW(
        WS_EX_APPWINDOW,
        szAppName,
        TEXT("Note Pad"),
        WS_OVERLAPPEDWINDOW | WS_VSCROLL,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL);

    if (hWnd == NULL)
    {
        MessageBoxW(NULL, L"Failed to create this window.", L"Message", 0);
        return 0;
    }

    ShowWindow(hWnd, cmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessageW(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }

    return 0;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static DWORD charset = DEFAULT_CHARSET;
    static int charWidth, lineHeight;
    static int clientWidth, clientHeight;

    switch (message)
    {
    case WM_CREATE:
    {
        HDC hdc = GetDC(hWnd);
        SelectObject(
            hdc, 
            CreateFontW(0, 0, 0, 0, 0, 0, 0, 0, charset, 0, 0, 0, FIXED_PITCH, 0));
        TEXTMETRICW tm;
        GetTextMetricsW(hdc, &tm);
        charWidth = tm.tmAveCharWidth;
        lineHeight = tm.tmHeight + tm.tmExternalLeading;
        DeleteObject(SelectObject(hdc, GetStockObject(SYSTEM_FONT)));
        ReleaseDC(hWnd, hdc);

        return 0;
    }
        
    case WM_SIZE:
    {
        clientWidth = LOWORD(lParam);
        clientHeight = HIWORD(lParam);

        SCROLLINFO si;
        si.cbSize = sizeof(si);
        si.fMask = SIF_RANGE | SIF_PAGE;
        si.nMin = 0;
        si.nMax = clientHeight / lineHeight - 1;
        si.nPage = clientHeight / lineHeight;

        SetScrollInfo(hWnd, SB_VERT, &si, TRUE);

        return 0;
    }

    case WM_CHAR:
    {
        switch (wParam)
        {
        case L'\r':
        {
            SCROLLINFO si;
            si.cbSize = sizeof(si);
            si.fMask = SIF_RANGE;
            GetScrollInfo(hWnd, SB_VERT, &si);
            si.nMax++;
            // ShowScrollBar(hWnd, SB_VERT, TRUE);
            SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
            break;
        }
        }

        return 0;
    }

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProcW(hWnd, message, wParam, lParam);
}

在代码中,当窗口弹出时,滚动条不会显示,因为 PageSize == nMax - nMin + 1,页面大小可以包含范围。但是当将 nMax 设置为 nMax++ 时,页面大小不能包含范围,滚动条应该显示在窗口的右侧。但事实并非如此,我无法更改范围!

在“关于滚动条”的“滚动条可见性”部分,要更改滚动条的范围,我不应该在 SetScrollInfo 之前调用 ShowScrollBar。

此问题由: Cannot set the range of a scrollbar by SetScrollInfo - Microsoft Q&A 总结而来

Windows API - Win32
Windows API - Win32
一组适用于桌面和服务器应用程序的核心 Windows 应用程序编程接口 (API)。 以前称为 Win32 API。
62 个问题
0 个注释 无注释
{count} 票

1 个答案

排序依据: 非常有帮助
  1. Tong Xu - MSFT 2,116 信誉分 Microsoft 供应商
    2024-05-17T05:31:28.12+00:00

    你好,
    欢迎来到 Microsoft Q&A!

    如果指定的页面大小包含滚动条的整个滚动范围,系统还会隐藏和禁用标准滚动条。

    就我而言,最初,页面大小包含滚动条的整个滚动范围,滚动条被禁用。即使更改滚动范围,除非调用 ShowScrollBar,否则不会启用滚动条。

    如果滚动条一开始没有被禁用,例如:si.nPage = clientHeight / lineHeight-2;。无需在 SetScrollInfo 之前调用 ShowScrollBar。因为滚动条没有被禁用。您可以更改滚动条的范围。

    在我看来,一旦滚动条被禁用,就需要调用ShowScrollBar以使滚动条可见。然后你可以改变滚动条的范围。这是设计使然。


    如果答案是正确的解决方案,请单击“接受答案”并请投赞成票。如果您对此答案有其他疑问,请点击“评论”。

    注意:如果您想接收此线程的相关电子邮件通知,请按照我们文档中的步骤启用电子邮件通知。

    0 个注释 无注释