Programming with Microsoft Visual C++.NET 6ed [Electronic resources]

George Shepherd, David Kruglinski

نسخه متنی -صفحه : 319/ 70
نمايش فراداده

Standard Common Controls

The standard common controls are the progress control, the slider control, the spin control, the list control, and the tree control. Figure 8-1 shows the Windows common controls dialog box example from this chapter.

Figure 8-1: The Windows common controls dialog box.

The Progress Control

The progress control is the easiest common control to program and is represented by the MFC CProgressCtrl class. It is generally used only for output. To initialize the progress control, you call the SetRange and SetPos member functions in your OnInitDialog function, and then you call SetPos anytime in your message handlers. The progress control shown in Figure 8-1 has a range of 0 to 100, which is the default.

The Slider Control

The slider control (class CSliderCtrl), sometimes called a trackbar, allows the user to set an "analog" value. (In the Ex07a example in Chapter 7, slider controls would have been more effective than the horizontal Loyalty and Reliability scroll bars.) If you specify a large range for this control—0 to 100 or more, for example—the slider's motion will appear continuous. If you specify a small range, such as 0 to 5, the slider will move in discrete increments. You can program tick marks to match the increments. In this discrete mode, you can use a slider to set such items as the display screen resolution, lens f-stop values, and so forth. The slider does not have a default range.

The slider is easier to program than the scroll bar because you don't have to map the WM_HSCROLL or WM_VSCROLL messages in the dialog class hosting the controls. As long as you set the range, the slider will move when the user slides it or clicks in the body of the slider. You might choose to map the scroll messages anyway if you want to show the position value in another control. The GetPos member function returns the current position value. The top slider in Figure 8-1 operates continuously in the range 0 to 100. The bottom slider has a range of 0 to 4, and those indexes are mapped to a series of double-precision values (4.0, 5.6, 8.0, 11.0, and 16.0).

The Spin Control

The spin control (class CSpinButtonCtrl), sometimes called a spin button, is a tiny scroll bar that's most often used in conjunction with an edit control. The edit control, located just ahead of the spin control in the dialog box's tabbing order, is known as the spin control's buddy. The idea is that the user holds down the left mouse button on the spin control to raise or lower the value in the edit control. The spin speed accelerates as the user continues to hold down the mouse button.

If your program uses an integer in the buddy, you can avoid C++ programming almost entirely. Just use Visual Studio to attach an integer data member to the edit control and set the spin control's range in the OnInitDialog function. (You probably won't want the spin control's default range, which runs backward from a minimum of 100 to a maximum of 0.) Don't forget to set the Auto Buddy and Set Buddy Integer properties for the spin control. You can call the SetRange and SetAccel member functions in your OnInitDialog function to change the range and the acceleration profile.

If you want your edit control to display a noninteger, such as a time or a floating-point number, you must map the spin control's WM_VSCROLL (or WM_HSCROLL) messages and write handler code to convert the spin control's integer to the buddy's value.

The List Control

You use the list control (class CListCtrl) if you want a list that contains images as well as text. In Figure 8-1, shown earlier, you can see a list control with a "list view" style and small icons. The elements are arranged in a grid, and the control includes horizontal scrolling. When the user selects an item, the control sends a notification message, which you map in your dialog class. That message handler can determine which item the user selected. Items are identified by a zero-based integer index.

Both the list control and the tree control get their graphic images from a common control element called an image list (class CImageList). Your program must assemble the image list from icons or bitmaps and then pass an image list pointer to the list control. Your OnInitDialog function is a good place to create and attach the image list and to assign text strings. The InsertItem member function serves this purpose.

List control programming is straightforward if you stick with strings and icons. If you implement drag-and-drop or if you need custom owner-drawn graphics, you've got more work to do.

The Tree Control

You're already familiar with tree controls if you've used Windows Explorer or Visual Studio's Solution Explorer. The MFC CTreeCtrl class makes it easy to add this same functionality to your own programs. In Figure 8-1, you saw a tree control that shows a modern American combined family. The user can expand and collapse elements by clicking the + and – buttons or by double-clicking the elements. The icon next to each item is programmed to change when the user selects the item with a single click.

The list control and the tree control have some things in common: They can both use the same image list, and they share some of the same notification messages. Their methods of identifying items are different, however. The tree control uses an HTREEITEM handle instead of an integer index. To insert an item, you call the InsertItem member function, but first you must build up a TV_INSERTSTRUCT structure that identifies (among other things) the string, the image list index, and the handle of the parent item (which is null for top-level items).

As with list controls, infinite customization possibilities are available for the tree control. For example, you can allow the user to edit items and to insert and delete items.

The WM_NOTIFY Message

The original Windows controls sent their notifications in WM_COMMAND messages. But the standard 32-bit wParam and lParam message parameters are not sufficient for the information that a common control needs to send to its parent. Microsoft solved this "bandwidth" problem by defining a new message, WM_NOTIFY. With the WM_NOTIFY message, wParam is the control ID and lParam is a pointer to an NMHDR structure, which is managed by the control. This C structure is defined by the following code:

typedef struct tagNMHDR {
HWND hwndFrom; // handle to control sending the message
UINT idFrom;   // ID of control sending the message
UINT code;     // control-specific notification code
} NMHDR;

However, many controls send WM_NOTIFY messages with pointers to structures larger than NMHDR. Those structures contain the three members above plus appended control-specific members. Many tree control notifications, for example, pass a pointer to an NM_TREEVIEWture that contains TV_ITEM structures, a drag point, and so forth. When Visual Studio maps a WM_NOTIFY message, it generates a pointer to the appropriate structure.