Example of Scrolling Text

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;