Cannot set the range of a scrollbar by SetScrollInfo

燕鹏 李 301 Reputation points
2023-08-28T19:18:44.4133333+00:00

I am reading Mr. Petzold's book, trying to make a note pad. When the caret comes to the last line of the client area and press the Enter key, I need to set the range of the scroll bar(adding 1 to the nMax), but I found that if I set the range of the scroll bar by SetScrollInfo, always failed, the range never be changed, unless I use the ShowScrollBar before SetScrollInfo.

Here is the minimum codes that can reproduce the failure.

#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);
}

In the code, when the window pops up, the scroll bar doesn't show because of PageSize == nMax - nMin + 1, page size can include the range. But when setting the nMax to nMax++, the page size cannot include the range, the scrollbar should show at the right side of the window. But it didn't, I cannot change the range!

By the section of Scroll Bar Visibility of About Scroll Bar, to change the range of a scrollbar, I shouldn't have called ShowScrollBar before SetScrollInfo.

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,469 questions
C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,584 questions
Windows 11
Windows 11
A Microsoft operating system designed for productivity, creativity, and ease of use.
8,591 questions
{count} votes

Accepted answer
  1. Jeanine Zhang-MSFT 9,346 Reputation points Microsoft Vendor
    2023-08-29T06:17:18.0066667+00:00

    Hello,

    Welcome to Microsoft Q&A!

    Sorry for misunderstanding you at first. Now I can reproduce your issue,

    The system also hides and disables a standard scroll bar if you specify a page size that includes the entire scroll range of the scroll bar.

    As far as I'm concerned, initially, the page size contains the entire scroll range of the scroll bar, the scroll bar is disabled. Even if you change the scroll range, the scroll bar will not be enabled unless you call ShowScrollBar.

    If the scroll bar is not disabled at first, for example: si.nPage = clientHeight / lineHeight-2;.You needn't call ShowScrollBar before SetScrollInfo. Because the scroll bar is not disabled. And you could change the range of the scroll bar.

    In my opinion, once the scroll bar is disabled, ShowScrollBar needs to be called to make the scroll bar visible. And then you could change the range of the scroll bar. This is by design.

    Thank you.

    Jeanine


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

0 additional answers

Sort by: Most helpful