滚动描述:
我们所看到的滚动其实是文本打印位置的改变,例如:向下滚动,本来我们的文本是从y坐标为0的位置开始排列向下打印,如果我们从y坐标为-1开始打印,这不就实现了滚动的效果(因为坐标为负是文本不显示)。
所需四个重要函数:
- 设置滚动条的范围:SetScrollRange
- 设置滚动滑块的位置:SetScrollPos
- 获取滚动条的范围:GetScrollRange
- 获取滚动滑块的位置:GetScrollPos
实例效果如下:
一、实现(需完成以下操作)
最开始是创建一个典型的Win32应用程序,然后对生成的代码进行添加修改
1. 添加滚动条
添加滚动条操作是在CreateWindowW函数中第三个参数中添加
WS_VSCROLL(垂直滚动条) 或 WS_HSCROLL(水平滚动条)。
2. 打印文本
这里使用了一个for循环打印文本
3. 设置滚动条的范围(SetScrollRange)
如 SetScrollRange(hWnd, SB_VERT, 0, 100, FALSE);
函数原型:
BOOL SetScrollRange(
HWND hWnd, // 窗口句柄
int nBar, // 滚动条类型
int nMinPos, // 滚动条的最小位置
int nMaxPos, // 滚动条的最大位置
BOOL bRedraw // 重绘标志
);
参数解释:
参数一: hWnd
[输入] 滚动条控件或带有标准滚动条窗体的句柄,由nBar参数值确定。
参数二 :nBar
[输入] 指定滚动条将被设置。这个参数可以是下表值中的一个,含义如下:
值 | 说明 |
---|---|
SB_CTL | 设置滚动条控件的范围。而参数hwnd必须是滚动条控件的句柄。 |
SB_HORZ | 设置窗体的标准水平滚动条的范围。 |
SB_VERT | 设置窗体的标准垂直滚动条的范围 |
参数三:nMinPos
[输入] 指定滚动位置的最小值。
参数四:nMaxPos
[输入] 指定滚动位置的最大值.。
参数五:bRedraw
[输入] 指定滚动条是否被重画以反映变化。如果这个参数为TRUE,滚动条将被重画;如果为FALSE则不被重画。
4. 处理滚动条消息
case WM_VSCROLL:
{
switch (LOWORD(wParam)) // 低16位
{
case SB_LINEDOWN:
case SB_LINEUP:
case SB_PAGEDOWN:
case SB_PAGEUP:
case SB_THUMBTRACK:
}
}
消息 | 作用 |
---|---|
SB_LINELEFT | 键盘左 或上 或鼠标点击左或上按钮 (三角形) |
SB_LINERIGHT | 键盘右或下 或鼠标点击右或下按钮 |
SB_PAGELEFT | 键盘 pgup 键(上翻页) 或鼠标点击滑块左或上面的空白 |
SB_PAGERIGHT | 键盘 pgdn键(下翻页)或鼠标点击滑块右或下面的空白 |
SB_THUMBTRACK | 鼠标拖动滑块 |
SB_TOP | 键盘home键 |
SB_BOTTOM | 键盘end键 |
5. 更新画面、设置滚动条位置
SetScrollPos(hWnd, SB_VERT, iVscrollPos, TRUE); // 设置滚动条位置
InvalidateRect(hWnd, NULL, TRUE); // 发送WM_PAINT消息,更新窗口
二、关键代码(有改动添加的部分)
1. 在窗口创建函数CreateWindowW中
添加第三个参数即可(用 | 进行连接)
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW | WS_VSCROLL,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
2.消息处理函数WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
size_t j;
TCHAR str[100];
TEXTMETRIC tm; // 结构体,用于计算字符的高度、宽度、间距等很多数据
static int cxChar, cyChar, iVscrollPos, cxClient, cyClient, y;
switch (message)
{
case WM_CREATE: // 窗口创建时,所产生的消息
{
HDC hdc;
hdc = GetDC(hWnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth; //字符平均宽度
cyChar = tm.tmHeight + tm.tmExternalLeading; //字符所需的高度
iVscrollPos = 0; // 滑块的初始位置
ReleaseDC(hWnd, hdc);
}
case WM_SIZE: // 窗口大小改变
{
cxClient = LOWORD(lParam); //客户区的宽度
cyClient = HIWORD(lParam); // 客户区的高度
y = cyClient / cyChar; // 计算一页中有多少行文本
SetScrollRange(hWnd, SB_VERT, 0, 50 - y, FALSE); //创建滚动条的范围
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// for循环打印文本
for (i = 0; i < 50; i++)
{
SetTextAlign(hdc, TA_LEFT | TA_TOP); //文本左对齐
// 安全字符串操作
StringCchPrintf(str, 100, TEXT("%d:I love you!"), i + 1);
StringCchLength(str, 100, &j);
TextOut(hdc, 0, (i - iVscrollPos)* cyChar, str, j);
TextOut(hdc, 20 * cxChar, (i - iVscrollPos)*cyChar, str, j);
SetTextAlign(hdc, TA_RIGHT | TA_TOP); // 文本右对齐
TextOut(hdc, 50 * cxChar, (i - iVscrollPos)*cyChar, str, j);
}
EndPaint(hWnd, &ps);
}
break;
case WM_VSCROLL:
{
switch (LOWORD(wParam))
{
case SB_LINEDOWN:
iVscrollPos += 1;
break;
case SB_LINEUP:
iVscrollPos -= 1;
break;
case SB_PAGEDOWN:
iVscrollPos += y;
break;
case SB_PAGEUP:
iVscrollPos -= y;
break;
case SB_THUMBTRACK:
iVscrollPos = HIWORD(wParam);
break;
}
iVscrollPos = min(50 - y, max(0, iVscrollPos)); //确保滑块不超出滚动条的范围
if (iVscrollPos != GetScrollPos(hWnd, SB_VERT))
{
SetScrollPos(hWnd, SB_VERT, iVscrollPos, TRUE); // 设置滚动条的位置
InvalidateRect(hWnd, NULL, TRUE); //发送WM_PAINT消息,更新窗口
}
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
今日一言:
你现在的努力,是为了以后有更多的选择。