The following example shows how to have your application scroll text in response to input from the horizontal and vertical scroll bars.
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
SCROLLINFO si;
/* These variables are required to display text. */
static int xClient; /* width of client area */
static int yClient; /* height of client area */
static int xClientMax; /* maximum width of client area */
static int xChar; /* horizontal scrolling unit */
static int yChar; /* vertical scrolling unit */
static int xUpper; /* average width of uppercase letters */
static int xPos; /* current horizontal scrolling position */
static int yPos; /* current vertical scrolling position */
static int xMax; /* maximum horiz. scrolling position */
static int yMax; /* maximum vert. scrolling position */
int xInc; /* horizontal scrolling increment */
int yInc; /* vertical scrolling increment */
int i; /* loop counter */
int x, y; /* horiz. and vert. printing coords */
int FirstLine; /* first line in the invalidated area */
int LastLine; /* last line in the invalidated area */
/* Create an array of lines to display. */
#define LINES 27
static char *abc[] = { "anteater", "bear", "cougar", "dingo",
"elephant", "frog", "gazelle", "hyena", "iguana", "jackal",
"kangaroo", "llama", "moose", "newt", "octopus", "penguin",
"quail", "rat", "squid", "tortoise", "urus", "vole",
"walrus", "xylophone", "yak", "zebra",
"This line contains many words, but no character. Go figure." };
switch (uMsg) {
case WM_CREATE :
/* Get the handle of the client area's device context. */
hdc = GetDC (hwnd);
/* Extract font dimensions from the text metrics. */
GetTextMetrics (hdc, &tm);
xChar = tm.tmAveCharWidth;
xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar/2;
yChar = tm.tmHeight + tm.tmExternalLeading;
/* Free the device context. */
ReleaseDC (hwnd, hdc);
/*
* Set an arbitrary maximum width for client area.
* (xClientMax is the sum of the widths of 48 average
* lowercase letters and 12 uppercase letters.)
*/
xClientMax = 48 * xChar + 12 * xUpper;
return 0;
case WM_SIZE:
/* Retrieve the dimensions of the client area. */
yClient = HIWORD (lParam);
xClient = LOWORD (lParam);
/*
* Determine the maximum vertical scrolling position.
* The two is added for extra space below the lines
* of text.
*/
yMax = max (0, LINES + 2 - yClient/yChar);
/*
* Make sure the current vertical scrolling position
* does not exceed the maximum.
*/
yPos = min (yPos, yMax);
/*
* Adjust the vertical scrolling range and scroll box
* position to reflect the new yMax and yPos values.
*/
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = 0;
si.nMax = yMax;
si.nPage = yClient / yChar;
si.nPos = yPos;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
/*
* Determine the maximum horizontal scrolling position.
* The two is added for extra space to the right of the
* lines of text.
*/
xMax = max (0, 2 + (xClientMax - xClient)/xChar);
/*
* Make sure the current horizontal scrolling position
* does not exceed the maximum.
*/
xPos = min (xPos, xMax);
/*
* Adjust the horizontal scrolling range and scroll box
* position to reflect the new xMax and xPos values.
*/
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
si.nMin = 0;
si.nMax = xMax;
si.nPage = xClient / xChar;
si.nPos = xPos;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
return 0;
case WM_PAINT:
/* Prepare the window for painting. */
hdc = BeginPaint(hwnd, &ps);
/*
* Use the current vertical scrolling position and
* coordinates of the invalid rectangle to determine
* the range of new lines that should be drawn in the
* client area.
*/
FirstLine = max (0, yPos + ps.rcPaint.top/yChar - 1);
LastLine = min (LINES, yPos + ps.rcPaint.bottom/yChar);
/* Display these lines. */
for (i = FirstLine;i < LastLine;i++) {
x = xChar * (1 - xPos);
y = yChar * (1 - yPos + i);
TextOut (hdc, x, y, abc[i], lstrlen(abc[i]));
}
/* Indicate that painting is finished. */
EndPaint(hwnd, &ps);
break;
case WM_HSCROLL:
switch(LOWORD (wParam)) {
/* User clicked shaft left of the scroll box. */
case SB_PAGEUP:
xInc = -8;
break;
/* User clicked shaft right of the scroll box. */
case SB_PAGEDOWN:
xInc = 8;
break;
/* User clicked the left arrow. */
case SB_LINEUP:
xInc = -1;
break;
/* User clicked the right arrow. */
case SB_LINEDOWN:
xInc = 1;
break;
/* User dragged the scroll box. */
case SB_THUMBTRACK:
xInc = HIWORD(wParam) - xPos;
break;
default:
xInc = 0;
}
/*
* If applying the horizontal scrolling increment does not
* take the scrolling position out of the scrolling range,
* increment the scrolling position, adjust the position
* of the scroll box, and update the window.
*/
if (xInc = max (-xPos, min (xInc, xMax - xPos))) {
xPos += xInc;
ScrollWindowEx (hwnd, -xChar * xInc, 0,
(CONST RECT *) NULL, (CONST RECT *) NULL,
(HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE);
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = xPos;
SetScrollInfo(hwnd, SB_HORZ, &si, TRUE);
UpdateWindow (hwnd);
}
return 0;
case WM_VSCROLL:
switch(LOWORD (wParam)) {
/* User clicked the shaft above the scroll box. */
case SB_PAGEUP:
yInc = min(-1, -yClient / yChar);
break;
/* User clicked the shaft below the scroll box. */
case SB_PAGEDOWN:
yInc = max(1, yClient / yChar);
break;
/* User clicked the top arrow. */
case SB_LINEUP:
yInc = -1;
break;
/* User clicked the bottom arrow. */
case SB_LINEDOWN:
yInc = 1;
break;
/* User dragged the scroll box. */
case SB_THUMBTRACK:
yInc = HIWORD(wParam) - yPos;
break;
default:
yInc = 0;
}
/*
* If applying the vertical scrolling increment does not
* take the scrolling position out of the scrolling range,
* increment the scrolling position, adjust the position
* of the scroll box, and update the window. UpdateWindow
* sends the WM_PAINT message.
*/
if (yInc = max(-yPos, min(yInc, yMax - yPos))) {
yPos += yInc;
ScrollWindow(hwnd, 0, -yChar * yInc,
(CONST RECT *) NULL, (CONST RECT *) NULL,
(HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE);
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = YPos;
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
UpdateWindow (hwnd);
}
return 0;