windows_programming_notes.nbk: Home | Index | Next Page: SCROLLINFO | Previous Page: SBM_SETRANGE


 Scroll Bar Controls in Win32

Summary

This article describes the functionality and design of scroll bar controls in the Microsoft Win32 Application Programming Interface (API). It covers common programming techniques associated with scroll bars; the functions used to manipulate scroll bars; the messages sent to scroll bars; and current limitations and known problems with scroll bars. Whenever possible, I have provided a workaround for a given limitation or bug. (15 printed pages)

Introduction

A scroll bar control is a rectangular window that contains a scroll box (usually called the thumb of the scroll bar) and two scroll arrows. The scroll bar control sends a notification message to its parent window whenever the user clicks the control with the mouse. The parent window is responsible for updating the parent window's contents and the position of the thumb (if necessary).

A scroll bar is part of a window, but a scroll bar control is actually a window itself. Unlike a scroll bar, a scroll bar control can be positioned anywhere in a window and used whenever the window needs to scroll input.

If you are comfortable with the use of scroll bars in Win16, you have already mastered most of the information in this technical article. There are, however, some differences between Win16 and Win32® scroll bars. The major difference is that Win32 scroll bars allow full 32-bit positioning while Win16 scroll bars allow 16-bit positioning. Currently, Win32 scroll bars are limited to 16 bits of positioning information during real-time scrolling (thumb tracking). However, I have come up with a workaround that will allow you to get the full 32 bits of positioning. (See the "Limitations" section of this technical article.)

Anatomy of a Scroll Bar

A scroll bar consists of a shaded shaft with a scroll arrow at each end and a scroll box (usually called a thumb) between the arrows (see Figure 1).

Figure 1. The anatomy of a scroll bar

A scroll bar represents the full range (overall length or width) of a data object such as a document or picture in the window's client area. The thumb represents the portion of the data object that is visible in the client area. The user can scroll the contents of the window by clicking one of the scroll arrows, by clicking the area in the shaded shaft, or by dragging the thumb. For example, when the user clicks the up arrow, the thumb moves up and the application scrolls the contents of the window by one unit (typically a single line or column). When the user clicks inside the shaft, the application scrolls the contents by one window. The amount of scrolling that occurs when the user drags the thumb is known as the scrolling range and is defined by the application developer.

Scroll Bar Styles

This section describes the styles that you can use when creating your scroll bar. These styles are also documented in the Platform SDK.

Style Functionality

Scroll Bar Techniques

Figure 2. The Sizebox sample screen

Scroll Bar Functions

Unlike other window classes, scroll bars are manipulated through functions. These functions are described in the sections below.

The first parameter to each function is the handle to the scroll bar control (or the handle to the owner window, if the scroll bar was created with the WS_HORZ or WS_VERT window style). The second parameter specifies the type of scroll bar to manipulate:

All scroll bar functions return an error in the following cases:

The following function sets the scroll position of the horizontal scroll bar control to 100 and forces a redraw of the scroll bar control:

    Err = SetScrollPos(hWndHorzScroll, SB_CTL, 100, TRUE);

Notification Messages

Interfacing with the Keyboard

The ability to manipulate the scroll bar with the keyboard instead of the mouse is not a built-in function of the scroll bar class. However, implementing scrolling behavior based on keyboard input is a fairly trivial task. One interesting problem associated with this task is determining what to do in the case of the PAGE_UP, PAGE_DOWN, HOME, and END keys. In the example below, I have associated PAGE_UP and PAGE_DOWN with the vertical scroll bar, and HOME and END with the horizontal scroll bar.

    case WM_KEYDOWN:
        switch (wParam) {
        case VK_UP:
            wScrollNotify = SB_LINEUP;
            uMessage = WM_VSCROLL;
            break;
        case VK_PRIOR:    //PAGEUP key
            wScrollNotify = SB_PAGEUP;
            uMessage = WM_VSCROLL;
            break;
        case VK_NEXT:     // PAGEDOWN key
            wScrollNotify = SB_PAGEDOWN;
            uMessage = WM_VSCROLL;
            break;
        case VK_DOWN:
            wScrollNotify = SB_LINEDOWN;
            uMessage = WM_VSCROLL;
            break;
        case VK_HOME:
            wScrollNotify = SB_BOTTOM;
            uMessage = WM_HSCROLL;
            break;
        case VK_END:
            wScrollNotify = SB_TOP;
            uMessage = WM_HSCROLL;
            break;
        case VK_RIGHT:
            wScrollNotify = SB_LINEDOWN;
            uMessage = WM_HSCROLL;
            break;
        case VK_LEFT:
            wScrollNotify = SB_LINEUP;
            uMessage = WM_HSCROLL;
            break;
        default:
            wScrollNotify = 0xFFFF;
            break;
        }
        if (wScrollNotify != -1) {
            SendMessage(hWnd, uMessage, MAKELONG(wScrollNotify, 0), 0L);
        }
        break;

Limitations

In Win32, you can use 32-bit values to set the range and position of the thumb in the scroll bar. However, if you are doing real-time thumb tracking using the SB_THUMBTRACK message, Win32 will give you only 16 bits of position data. This is because the position data is returned in the HIWORD of the lParam. To get around this limitation, you need to retrieve the full 32-bit value explicitly.

    /* User dragged the thumb. */
    case SB_THUMBPOSITION:
        xNewPos = GetScrollPos(hWndHorzScroll, SB_CTL);
        break;
    case SB_THUMBTRACK:
        {
            SCROLLINFO si;
            si.cbSize = sizeof(si);
            si.fMask = SIF_TRACKPOS;
            GetScrollInfo(hWndHorzScroll, SB_CTL);
            xNewPos = si.nTrackPos;
        }
        break;

The Scroll32 sample that is included with this technical article demonstrates a different, less reliable technique, based on estimating the scroll position from the cursor position. Run that sample and drag the mouse along either the vertical or the horizontal scroll bar. You will see the scroll position updated in the text at the bottom of the screen. You can also set a specific scroll range and scroll position with this sample.

One problem with the method in the Scroll32 sample manifests itself in the following scenario:

The user clicks to the right of the thumb and drags the thumb to set the scroll position.

The user then clicks to the left of the thumb to set the scroll position. At this point, the actual scroll position will be off by the distance between the left side and the right side of the thumb. You can correct this problem by calculating the scroll position based on the center of the thumb. That is, when the user clicks the thumb, get the distance between the center of the thumb and the actual cursor point and subtract that distance from the position before calculating your cursor-to-scroll-position ratio.

Conclusion

Scroll bars are very similar in Win16 and Win32. The major difference is that Win32 scroll bars allow full 32-bit positioning while Win16 scroll bars allow 16-bit positioning. If you are already comfortable working with scroll bar controls in Win16, you will be pleasantly surprised to find that there is very little new work to do in Win32. In fact, if you do not need 32-bit precision in your positioning, you will not need to change your code at all. If you do need 32-bit precision, you will need to work around the real-time scrolling limitation that I explained in the previous section.


windows_programming_notes.nbk: Home | Index | Next Page: SCROLLINFO | Previous Page: SBM_SETRANGE


Notebook exported on Monday, 7 July 2008, 18:56:50 PM Eastern Daylight Time