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 horizontal scrolling position
static int yMax; // maximum vertical scrolling position
int xInc; // horizontal scrolling increment
int yInc; // vertical scrolling increment
int i; // loop counter
int x, y; // horizontal and vertical coordinates
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 to 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;