用于创建窗口的 CreateWindow 函数的第三个参数可以设置 WS_HSCROLL(水平滚动条) 和 WS_VSCROLL(垂直滚动条) 这两个风格标识符,以标识窗口附带水平滚动条和(或)垂直滚动条
当用户单击或拖动窗口滚动条时,Windows 向窗口过程发送 WM_HSCROLL(水平滚动) 消息或 WM_VSCROLL(垂直滚动) 消息,鼠标按下与鼠标松开都会产生这些消息(即一个动作至少会产生两条消息)。消息伴随着消息参数,lParam 的值为滚动条的句柄(当是窗口的滚动条时,此值为 NULL 可以忽略),wParam 的低位字代表鼠标在滚动条上的动作:
向上(左)滚动一行:SB_LINEUP
向下(右)滚动一行:SB_LINEDOWN
向上(左)滚动一页:SB_PAGEUP
向下(右)滚动一页:SB_PAGEDOWN
拖动滚动条不放:SB_THUMBTRACK(一直发送),wParam 的高位字是用户拖动滑块的当前位置
拖动滚动条时释放鼠标:SB_THUMBPOSITION,wParam 的高位字是松开鼠标键时,滑块的最终位置
松开鼠标键时:SB_ENDSCROLL
调用 SetScrollRange 函数可以设置滚动条的范围:
BOOL SetScrollRange(
HWND hWnd, // 窗口的句柄
int nBar, // 滚动条类型(SB_VERT 或 SB_HORZ)
int nMinPos, // 最小位置
int nMaxPos, // 最大位置
BOOL bRedraw // 是否需要 Windows 根据新的范围来重绘滚动条(若编程时调用其它函数来调整滚动条的显示,则最好设为FALSE,避免过多重绘)
);
调用 SetScrollPos 函数可以调整滚动条的位置:
int SetScrollPos(
HWND hWnd, // 窗口的句柄
int nBar, // 滚动条类型(SB_VERT 或 SB_HORZ)
int nPos, // 要设置的滚动条的位置(必须在最小位置和最大位置之间)
BOOL bRedraw // 是否需要 Windows 根据新的范围来重绘滚动条(若编程时调用其它函数来调整滚动条的显示,则最好设为FALSE,避免过多重绘)
);
调用 GetScrollRange 函数可以获取滚动条的范围:
BOOL GetScrollRange(
HWND hWnd,
int nBar,
LPINT lpMinPos, // 最小位置
LPINT lpMaxPos // 最大位置
);
调用 GetScrollPos函数可以获取滚动条的位置:
int GetScrollPos(
HWND hWnd,
int nBar
);
typedef struct tagSCROLLINFO {
UINT cbSize; // 设为 sizeof (SCROLLINFO)
UINT fMask; // 要设置和获取的值
int nMin; // 范围的最小值
int nMax; // 范围的最大值
UINT nPage; // 页面大小
int nPos; // 当前位置
int nTrackPos; // 当前追踪位置
} SCROLLINFO, *LPSCROLLINFO;
typedef SCROLLINFO CONST *LPCSCROLLINFO;
cbSize 字段表示该结构的大小,通常被填充为 sizeof(SCROLLINFO) ,这样方便新版本的 Windows 扩充字段。
fMask 字段把 SIF 为前缀的标志用位或组合起来,表示设置和获取的值。
SIF_RANGE:该标志表示滚动条范围,此时 nMin、nMax 有效
SIF_POS:该标志表示滚动条位置,此时 nPos 有效
SIF_PAGE:该标志表示页面大小,此时 nPage 有效
SIF_TRACKPOS:该标志表示当前滑块的位置(只用于 GetScrollInfo 中,只在 SB_THUMBTRACK 和 SB_THUMBPOSITION 有效),nTrackPos 有效
SIF_DISABLENOSCROLL:该标志表示当滚动条不显示时,显示禁用的滚动条样式
SIF_ALL:该标志是 SIF_RANGE、SIF_POS、SIF_PAGE、SIF_TRACKPOS 的组合
int SetScrollInfo(
HWND hwnd, // 当前窗口句柄
int fnBar, // 滚动条类型(SB_VERT 或者 SB_HORZ)
LPCSCROLLINFO lpsi, // SCROLLINFO 结构的地址
BOOL fRedraw // 是否重绘的标志
);
BOOL GetScrollInfo(
HWND hwnd, // 当前窗口句柄
int fnBar, // 滚动条类型(SB_VERT 或者 SB_HORZ)
LPCSCROLLINFO lpsi, // SCROLLINFO 结构的地址
);
BOOL ScrollWindow(
HWND hWnd, // 当前窗口句柄
int XAmount, // 水平滚动量,为负则向左滚动
int YAmount, // 垂直滚动量,为负则向上滚动
const RECT *lpRect, // 指定滚动客户区矩形的范围
const RECT *lpClipRect // 指定滚动的裁剪区域
);
/*-----------------------------------------------
SYSMETS.H -- System metrics display structure
-----------------------------------------------*/
#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))
struct
{
int iIndex ;
TCHAR * szLabel ;
TCHAR * szDesc ;
}
sysmetrics [] =
{
SM_CXSCREEN, TEXT ("SM_CXSCREEN"),
TEXT ("Screen width in pixels"),
SM_CYSCREEN, TEXT ("SM_CYSCREEN"),
TEXT ("Screen height in pixels"),
SM_CXVSCROLL, TEXT ("SM_CXVSCROLL"),
TEXT ("Vertical scroll width"),
SM_CYHSCROLL, TEXT ("SM_CYHSCROLL"),
TEXT ("Horizontal scroll height"),
SM_CYCAPTION, TEXT ("SM_CYCAPTION"),
TEXT ("Caption bar height"),
SM_CXBORDER, TEXT ("SM_CXBORDER"),
TEXT ("Window border width"),
SM_CYBORDER, TEXT ("SM_CYBORDER"),
TEXT ("Window border height"),
SM_CXFIXEDFRAME, TEXT ("SM_CXFIXEDFRAME"),
TEXT ("Dialog window frame width"),
SM_CYFIXEDFRAME, TEXT ("SM_CYFIXEDFRAME"),
TEXT ("Dialog window frame height"),
SM_CYVTHUMB, TEXT ("SM_CYVTHUMB"),
TEXT ("Vertical scroll thumb height"),
SM_CXHTHUMB, TEXT ("SM_CXHTHUMB"),
TEXT ("Horizontal scroll thumb width"),
SM_CXICON, TEXT ("SM_CXICON"),
TEXT ("Icon width"),
SM_CYICON, TEXT ("SM_CYICON"),
TEXT ("Icon height"),
SM_CXCURSOR, TEXT ("SM_CXCURSOR"),
TEXT ("Cursor width"),
SM_CYCURSOR, TEXT ("SM_CYCURSOR"),
TEXT ("Cursor height"),
SM_CYMENU, TEXT ("SM_CYMENU"),
TEXT ("Menu bar height"),
SM_CXFULLSCREEN, TEXT ("SM_CXFULLSCREEN"),
TEXT ("Full screen client area width"),
SM_CYFULLSCREEN, TEXT ("SM_CYFULLSCREEN"),
TEXT ("Full screen client area height"),
SM_CYKANJIWINDOW, TEXT ("SM_CYKANJIWINDOW"),
TEXT ("Kanji window height"),
SM_MOUSEPRESENT, TEXT ("SM_MOUSEPRESENT"),
TEXT ("Mouse present flag"),
SM_CYVSCROLL, TEXT ("SM_CYVSCROLL"),
TEXT ("Vertical scroll arrow height"),
SM_CXHSCROLL, TEXT ("SM_CXHSCROLL"),
TEXT ("Horizontal scroll arrow width"),
SM_DEBUG, TEXT ("SM_DEBUG"),
TEXT ("Debug version flag"),
SM_SWAPBUTTON, TEXT ("SM_SWAPBUTTON"),
TEXT ("Mouse buttons swapped flag"),
SM_CXMIN, TEXT ("SM_CXMIN"),
TEXT ("Minimum window width"),
SM_CYMIN, TEXT ("SM_CYMIN"),
TEXT ("Minimum window height"),
SM_CXSIZE, TEXT ("SM_CXSIZE"),
TEXT ("Min/Max/Close button width"),
SM_CYSIZE, TEXT ("SM_CYSIZE"),
TEXT ("Min/Max/Close button height"),
SM_CXSIZEFRAME, TEXT ("SM_CXSIZEFRAME"),
TEXT ("Window sizing frame width"),
SM_CYSIZEFRAME, TEXT ("SM_CYSIZEFRAME"),
TEXT ("Window sizing frame height"),
SM_CXMINTRACK, TEXT ("SM_CXMINTRACK"),
TEXT ("Minimum window tracking width"),
SM_CYMINTRACK, TEXT ("SM_CYMINTRACK"),
TEXT ("Minimum window tracking height"),
SM_CXDOUBLECLK, TEXT ("SM_CXDOUBLECLK"),
TEXT ("Double click x tolerance"),
SM_CYDOUBLECLK, TEXT ("SM_CYDOUBLECLK"),
TEXT ("Double click y tolerance"),
SM_CXICONSPACING, TEXT ("SM_CXICONSPACING"),
TEXT ("Horizontal icon spacing"),
SM_CYICONSPACING, TEXT ("SM_CYICONSPACING"),
TEXT ("Vertical icon spacing"),
SM_MENUDROPALIGNMENT, TEXT ("SM_MENUDROPALIGNMENT"),
TEXT ("Left or right menu drop"),
SM_PENWINDOWS, TEXT ("SM_PENWINDOWS"),
TEXT ("Pen extensions installed"),
SM_DBCSENABLED, TEXT ("SM_DBCSENABLED"),
TEXT ("Double-Byte Char Set enabled"),
SM_CMOUSEBUTTONS, TEXT ("SM_CMOUSEBUTTONS"),
TEXT ("Number of mouse buttons"),
SM_SECURE, TEXT ("SM_SECURE"),
TEXT ("Security present flag"),
SM_CXEDGE, TEXT ("SM_CXEDGE"),
TEXT ("3-D border width"),
SM_CYEDGE, TEXT ("SM_CYEDGE"),
TEXT ("3-D border height"),
SM_CXMINSPACING, TEXT ("SM_CXMINSPACING"),
TEXT ("Minimized window spacing width"),
SM_CYMINSPACING, TEXT ("SM_CYMINSPACING"),
TEXT ("Minimized window spacing height"),
SM_CXSMICON, TEXT ("SM_CXSMICON"),
TEXT ("Small icon width"),
SM_CYSMICON, TEXT ("SM_CYSMICON"),
TEXT ("Small icon height"),
SM_CYSMCAPTION, TEXT ("SM_CYSMCAPTION"),
TEXT ("Small caption height"),
SM_CXSMSIZE, TEXT ("SM_CXSMSIZE"),
TEXT ("Small caption button width"),
SM_CYSMSIZE, TEXT ("SM_CYSMSIZE"),
TEXT ("Small caption button height"),
SM_CXMENUSIZE, TEXT ("SM_CXMENUSIZE"),
TEXT ("Menu bar button width"),
SM_CYMENUSIZE, TEXT ("SM_CYMENUSIZE"),
TEXT ("Menu bar button height"),
SM_ARRANGE, TEXT ("SM_ARRANGE"),
TEXT ("How minimized windows arranged"),
SM_CXMINIMIZED, TEXT ("SM_CXMINIMIZED"),
TEXT ("Minimized window width"),
SM_CYMINIMIZED, TEXT ("SM_CYMINIMIZED"),
TEXT ("Minimized window height"),
SM_CXMAXTRACK, TEXT ("SM_CXMAXTRACK"),
TEXT ("Maximum dragable width"),
SM_CYMAXTRACK, TEXT ("SM_CYMAXTRACK"),
TEXT ("Maximum dragable height"),
SM_CXMAXIMIZED, TEXT ("SM_CXMAXIMIZED"),
TEXT ("Width of maximized window"),
SM_CYMAXIMIZED, TEXT ("SM_CYMAXIMIZED"),
TEXT ("Height of maximized window"),
SM_NETWORK, TEXT ("SM_NETWORK"),
TEXT ("Network present flag"),
SM_CLEANBOOT, TEXT ("SM_CLEANBOOT"),
TEXT ("How system was booted"),
SM_CXDRAG, TEXT ("SM_CXDRAG"),
TEXT ("Avoid drag x tolerance"),
SM_CYDRAG, TEXT ("SM_CYDRAG"),
TEXT ("Avoid drag y tolerance"),
SM_SHOWSOUNDS, TEXT ("SM_SHOWSOUNDS"),
TEXT ("Present sounds visually"),
SM_CXMENUCHECK, TEXT ("SM_CXMENUCHECK"),
TEXT ("Menu check-mark width"),
SM_CYMENUCHECK, TEXT ("SM_CYMENUCHECK"),
TEXT ("Menu check-mark height"),
SM_SLOWMACHINE, TEXT ("SM_SLOWMACHINE"),
TEXT ("Slow processor flag"),
SM_MIDEASTENABLED, TEXT ("SM_MIDEASTENABLED"),
TEXT ("Hebrew and Arabic enabled flag"),
SM_MOUSEWHEELPRESENT, TEXT ("SM_MOUSEWHEELPRESENT"),
TEXT ("Mouse wheel present flag"),
SM_XVIRTUALSCREEN, TEXT ("SM_XVIRTUALSCREEN"),
TEXT ("Virtual screen x origin"),
SM_YVIRTUALSCREEN, TEXT ("SM_YVIRTUALSCREEN"),
TEXT ("Virtual screen y origin"),
SM_CXVIRTUALSCREEN, TEXT ("SM_CXVIRTUALSCREEN"),
TEXT ("Virtual screen width"),
SM_CYVIRTUALSCREEN, TEXT ("SM_CYVIRTUALSCREEN"),
TEXT ("Virtual screen height"),
SM_CMONITORS, TEXT ("SM_CMONITORS"),
TEXT ("Number of monitors"),
SM_SAMEDISPLAYFORMAT, TEXT ("SM_SAMEDISPLAYFORMAT"),
TEXT ("Same color format flag")
};
#include "SysMets.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
static int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth;
int iVertPos, iHorzPos, iBeginLine, iEndLine, i, x, y;
size_t nLength;
SCROLLINFO si;
TCHAR szBuffer[100];
switch (message) {
case WM_CREATE:
hdc = GetDC(hwnd);
GetTextMetrics(hdc, &tm);
cxChar = tm.tmAveCharWidth;
cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;
cyChar = tm.tmHeight + tm.tmExternalLeading;
iMaxWidth = cxCaps * 22 + cxChar * 40;
ReleaseDC(hwnd, hdc);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = NUMLINES - 1;
si.nPage = cyClient / cyChar;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_DISABLENOSCROLL;
si.nMin = 0;
si.nMax = iMaxWidth / cxChar + 5;
si.nPage = cxClient / cxChar;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
return 0;
case WM_VSCROLL:
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, &si);
iVertPos = si.nPos;
switch (LOWORD(wParam)) {
case SB_LINEUP:
si.nPos -= 1;
break;
case SB_LINEDOWN:
si.nPos += 1;
break;
case SB_PAGEUP:
si.nPos -= si.nPage;
break;
case SB_PAGEDOWN:
si.nPos += si.nPage;
break;
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
}
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
GetScrollInfo(hwnd, SB_VERT, &si);
if (si.nPos != iVertPos) {
ScrollWindow(hwnd, 0, cyChar * (iVertPos - si.nPos), NULL, NULL);
}
return 0;
case WM_HSCROLL:
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_HORZ, &si);
iHorzPos = si.nPos;
switch (LOWORD(wParam)) {
case SB_LINELEFT:
si.nPos -= 1;
break;
case SB_LINERIGHT:
si.nPos += 1;
break;
case SB_PAGELEFT:
si.nPos -= si.nPage;
break;
case SB_PAGERIGHT:
si.nPos += si.nPage;
break;
case SB_THUMBTRACK:
si.nPos = si.nTrackPos;
break;
}
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
GetScrollInfo(hwnd, SB_HORZ, &si);
if (si.nPos != iHorzPos) {
ScrollWindow(hwnd, cxChar * (iHorzPos - si.nPos), 0, NULL, NULL);
}
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
si.cbSize = sizeof(si);
si.fMask = SIF_ALL;
GetScrollInfo(hwnd, SB_VERT, &si);
iVertPos = si.nPos;
GetScrollInfo(hwnd, SB_HORZ, &si);
iHorzPos = si.nPos;
// Control the line range
iBeginLine = max(0, iVertPos + (ps.rcPaint.top / cyChar));
iEndLine = min(NUMLINES - 1, iVertPos + (ps.rcPaint.bottom / cyChar));
for (i = iBeginLine; i <= iEndLine; i++) {
x = cxChar * (1 - iHorzPos);
y = cyChar * (i - iVertPos);
StringCchPrintf(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), sysmetrics[i].szLabel);
StringCchLength(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), &nLength);
TextOut(hdc, x, y, szBuffer, nLength);
StringCchPrintf(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), sysmetrics[i].szDesc);
StringCchLength(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), &nLength);
TextOut(hdc, x + cxCaps * 22, y, szBuffer, nLength);
StringCchPrintf(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), TEXT("%5d"), sysmetrics[i].iIndex);
StringCchLength(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), &nLength);
TextOut(hdc, x + cxCaps * 22 + cxChar * 40, y, szBuffer, nLength);
}
EndPaint(hwnd, &ps);
return 0;
case WM_CLOSE:
if (MessageBox(hwnd, TEXT("Do you really want to quit?"), TEXT("Please confirm:"), MB_ICONQUESTION | MB_OKCANCEL) == IDOK) {
DestroyWindow(hwnd);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
LPCTSTR lpszClassName = TEXT("ScrollDemo");
LPCTSTR lpszWindowName = TEXT("Scroll Demo");
WNDCLASS wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hInstance = hInstance;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = lpszClassName;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClass(&wndclass)) {
MessageBox(NULL, TEXT("This program requires Windows NT!"), lpszWindowName, MB_ICONERROR);
return 0;
}
HWND hwnd = CreateWindow(
lpszClassName,
lpszWindowName,
WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
总的来说,SYSMET 程序可以细分为如下结构:
对 WM_CREATE 的消息的响应,获取系统字符的各个参数。
对 WM_SIZE 消息的响应,改变水平滚动条和垂直滚动条的范围 (nMin, nMax) 和页面大小 (nPage)
对 WM_VSCROLL 消息的响应,根据 LOWORD(wParam) 改变垂直滚动条滑块的位置 (nPos),并根据位置变化的偏移量,滚动客户区(ScrollWindow)
对 WM_HSCROLL 消息的响应,根据 LOWORD(wParam) 改变水平滚动条滑块的位置 (nPos),并根据位置变化的偏移量,滚动客户区 (ScrollWindow)
对 WM_PAINT 消息的响应,根据滚动条滑块位置和 PAINTSTRUCT 的 rcPaint 无效矩形区域信息计算出,文本绘制的开始行(iBeginLine) 和结束行 (iEndLine); 并根据滚动条滑块位置,计算出文本输出的起始水平位置 (x) 和垂直位置 (y),并输出文本 (TextOut)
🖊️ 本文由 Alone Café 创作,如果您觉得本文让您有所收获,请随意赞赏 🥺
⚖️ 本文以 CC BY-NC-SA 4.0,即《署名-非商业性使用-相同方式共享 4.0 国际许可协议》进行许可
👨⚖️ 本站所发表的文章除注明转载或出处外,均为本站作者原创或翻译,转载前请务必署名并遵守上述协议
🔗 原文链接:https://alone.cafe/2018/05/gun-dong-tiao
📅 最后更新:2018年05月25日 Friday 08:25
Update your browser to view this website correctly. Update my browser now