1. 创建一个窗口,并设置窗口样式为可滚动的(WS_VSCROLL)。
2. 在窗口的WM_CREATE消息中,创建一个字体,并将其保存到全局变量中。
3. 在窗口的WM_SIZE消息中,获取窗口的客户区大小,并计算出文本输出区域的宽度和高度。
4. 根据窗口的客户区大小,调整滑动条的范围和位置。设置滑动条的范围为文本输出区域的高度,并设置滑块的大小为窗口的高度。
5. 在WM_VSCROLL消息中,根据滑动条的位置,计算出需要显示的文本的起始行数,并调用InvalidateRect函数重新绘制窗口。
#include <windows.h>// 窗口标题和类名const char g_szClassName[] = "myWindowClass";// 全局变量HFONT g_hFont;LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ static int nScrollPos = 0; static int nCharHeight; static int nLineCount; static int nMaxScrollPos; switch (msg) { case WM_CREATE: { // 创建字体 LOGFONT lf = {0}; lf.lfHeight = -MulDiv(12, GetDeviceCaps(GetDC(hwnd), LOGPIXELSY), 72); g_hFont = CreateFontIndirect(&lf); // 计算字符高度 HDC hdc = GetDC(hwnd); SelectObject(hdc, g_hFont); TEXTMETRIC tm; GetTextMetrics(hdc, &tm); nCharHeight = tm.tmHeight; ReleaseDC(hwnd, hdc); // 设置滑动条的最大值和页面大小 nLineCount = 100; // 假设有100行文本 nMaxScrollPos = nLineCount - 1; SetScrollRange(hwnd, SB_VERT, 0, nMaxScrollPos, TRUE); SetScrollPage(hwnd, SB_VERT, 10); // 每次滚动10行 return 0; } case WM_SIZE: { int nClientHeight = HIWORD(lParam); // 根据窗口的客户区大小调整滑动条的范围和位置 SCROLLINFO si = {0}; si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE; si.nMin = 0; si.nMax = nMaxScrollPos; si.nPage = nClientHeight / nCharHeight; si.nPos = nScrollPos; SetScrollInfo(hwnd, SB_VERT, &si, TRUE); return 0; } case WM_VSCROLL: { int nScrollCode = LOWORD(wParam); switch (nScrollCode) { case SB_LINEUP: nScrollPos -= 1; break; case SB_LINEDOWN: nScrollPos += 1; break; case SB_PAGEUP: nScrollPos -= nClientHeight / nCharHeight; break; case SB_PAGEDOWN: nScrollPos += nClientHeight / nCharHeight; break; case SB_TOP: nScrollPos = 0; break; case SB_BOTTOM: nScrollPos = nMaxScrollPos; break; case SB_THUMBPOSITION: nScrollPos = HIWORD(wParam); break; } nScrollPos = max(0, min(nScrollPos, nMaxScrollPos)); SetScrollPos(hwnd, SB_VERT, nScrollPos, TRUE); // 重新绘制窗口 InvalidateRect(hwnd, NULL, TRUE); return 0; } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); // 计算可见的文本行数和起始行号 int nFirstVisibleLine = nScrollPos; int nLastVisibleLine = min(nFirstVisibleLine + (nClientHeight / nCharHeight), nLineCount); SelectObject(hdc, g_hFont); SetBkMode(hdc, TRANSPARENT); // 循环输出可见的文本行 for (int i = nFirstVisibleLine; i < nLastVisibleLine; ++i) { TEXTOUT(hdc, 0, (i - nFirstVisibleLine) * nCharHeight, "Hello, World!", 13); } EndPaint(hwnd, &ps); return 0; } case WM_DESTROY: { // 销毁字体 DeleteObject(g_hFont); PostQuitMessage(0); return 0; } } return DefWindowProc(hwnd, msg, wParam, lParam);}int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){ // 注册窗口类 WNDCLASSEX wc = {0}; wc.cbSize = sizeof(wc); wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, "窗口类注册失败!", "错误", MB_ICONERROR | MB_OK); return -1; } // 创建窗口 HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "自适应窗口", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, NULL, NULL, hInstance, NULL); if (hwnd == NULL) { MessageBox(NULL, "窗口创建失败!", "错误", MB_ICONERROR | MB_OK); return -1; } // 显示窗口 ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); // 消息循环 MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam;}
这段代码创建了一个具有垂直滑动条的自适应窗口,并使用TEXTOUT函数输出文本。你可以将"Hello, World!"替换为其他需要输出的文本。请注意,此代码仅为示例,实际应用可能需要进一步添加错误处理和优化。