我正在读佩佐尔德先生的书,试图做一个记事本。当插入符号到达工作区的最后一行并按 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 总结而来