In this section, you will learn about controls that were first offered
in Windows 95:
The up-down or spin control
The slider control, also known as the trackbar control
The progress control
You will build one sample program in this section. As each control is discussed,
it will be added to the sample project.
A Common Control Overview
When Windows 95 was released, it included a number of brand-new controls.
These controls, known collectively as the common controls, added exciting
features to the Windows user interface. The controls covered in this book,
along with their associated MFC classes, are shown in Table 16.1.
Table 16.1. Some common controls and their MFC classes.
Control
Class
Image List
CImageList
List
CListCtrl
Progress
CProgressCtrl
Slider (Trackbar)
CSliderCtrl
Up-down (Spin)
CSpinButtonCtrl
Tree
CTreeCtrl
Using the Up-Down Control
The up-down control, often called the spin control, is a pair of small
arrows that resemble the ends of a scrollbar but are smaller. Up-down controls
are often used to adjust the value of another control that is associated
with the up-down control.
New Term: The control that is paired
with the up-down control is known as the
buddycontrol. The
buddy control is normally an edit control.
An up-down control can also be aligned horizontally. A horizontal up-down
control is not called a left-right control; it keeps its original name.
By default, clicking the up arrow decreases the value of the buddy control,
and clicking the down arrow increases the value contained in the buddy
control. The up and down arrows work a lot like a scrollbar in a word-processing
document--clicking the up arrow moves you to a lower-numbered page, clicking
the down arrow moves you to a higher-numbered page. This behavior is confusing
to most people; fortunately, it's easy to change, as you see in the section
"Changing the Behavior of the Up-Down Control."
Up-down controls are ideal for situations where a set of values can
be scrolled by a user. If the user needs to adjust the values by only a
few units, an up-down control is perfect because it enables the user to
select a new value with only a few mouse clicks.
An up-down control is very easy to use. To use the default functionality
of the up-down control, you need to write exactly zero lines of source
code! Even the most advanced uses for up-down controls require just a few
lines of source code; most of the code is written by ClassWizard.
The Sample Program
For the examples created in this section, you use a dialog box-based project
named Controls. This project starts with an up-down control; later in the
chapter, you add a slider and a progress control.
To create the Controls project, use AppWizard to create a new project
workspace. Select a dialog box-based project and click the Finish button.
Adding an Up-Down Control to a Dialog Box
Adding an up-down control to the Controls dialog box is just like adding
other controls. Open the main dialog box in the dialog box editor by selecting
the ResourceView tab in the project workspace and opening the Dialog folder.
Open the IDD_CONTROLS_DIALOG by double-clicking the dialog box
icon or by right-clicking the icon and selecting Open from the pop-up menu.
To place the up-down control, you can either drag and drop the control
from the control palette to the main dialog box, or you can select the
up-down control on the tool palette using the mouse and then click the
desired position in the main dialog box.
Open the Properties dialog box for the up-down control by right-clicking
the control and selecting Properties from the pop-up menu. Change the control's
resource ID to IDC_SPIN. All other properties should be set to
their default values.
Up-Down Control Properties
As with other controls, up-down controls have properties that you can change
using the Developer Studio resource editor. The properties available for
an up-down control include the following:
ID is used for the up-down control's resource ID. A default resource
ID, such as IDC_SPIN1, is supplied by Developer Studio.
Visible is used to indicate that the control is initially visible.
This check box is usually checked.
Disabled is used to indicate the control should be initially disabled.
This check box is usually cleared.
Group is used to mark the first control in a group. This check box
is usually cleared.
Tab Stop indicates that this control can be reached by pressing
Tab on the keyboard. This check box is usually left unchecked; this is
different from most controls, due to the fact that the up-down control
is typically used to change the value of the buddy control. Normally the
buddy control has the tabstop property enabled.
Help ID indicates that a context-sensitive help ID should be generated
for this control.
Orientation indicates whether the up-down control should be vertical
or horizontal. The default selection is vertical.
Alignment specifies how the buddy control and up-down control are
associated with each other. Possible values are Right, Left, and Unattached.
The default value is Unattached, but in most cases, you should select Left
or Right.
Auto Buddy indicates whether the up-down control should use the
previous control in the tab order as its buddy control. This check box
is cleared by default but should be checked in most cases. If this box
is not checked, the up-down control will not be associated with a buddy
control. You can still form this association by command, which is discussed
in the next section.
Set Buddy Integer indicates that the up-down control should set
the value of the attached buddy control. This check box is cleared by default
but should be checked in most cases.
No Thousands indicates that no separator should be provided for
a value greater than 1,000 in the up-down control. This check box is usually
cleared.
Wrap indicates that the up-down control should "wrap around" after
reaching its minimum or maximum value. If this option is not selected,
the up-down control stops after reaching its minimum or maximum limit.
This check box is usually cleared.
Arrow Key indicates that the keyboard's arrow keys can be used to
change the value of the up-down control. This check box is usually cleared.
Adding a Buddy Control
The easiest way to add a buddy control to an up-down control requires no
source code; instead, you use the dialog box editor. Follow these steps
to associate an edit control with an up-down control:
1. Add an edit control to the dialog box. Most users expect the up-down
control to be placed against the buddy control; it helps emphasize the
connection between the two controls.
2. Open the properties dialog box for the edit control and change the
resource ID to IDC_EDIT. All other properties should be set to
their default values.
3. Set the tab order for the edit control so that it is the control
immediately before the up-down control. You can select the tab order by
choosing Tab Order from the Layout menu (or press Ctrl+D). Each control
is displayed with a small label that represents the control tab order.
To change the tab order, use the mouse to click each control in the new
tab order sequence.
4. Open the properties dialog box for the up-down control and set the
alignment value to Right. This aligns the up-down control on the right
side of the buddy control.
5. Keep the Properties dialog box open and check the Auto Buddy and
Set Buddy Integer check boxes.
The IDD_CONTROLS_DIALOG with an up-down control and the buddy
edit control is shown in Figure 16.1.
figure 16.1
The main dialog box used in the Controls sample program, including
the up-down control and buddy control.
Believe it or not, that's all there is to using an up-down control.
If you compile and execute the Controls project, you can use the up-down
control to change the value contained in the edit control.
CAUTION: Assigning a tab
stop to an up-down control tends to confuse the user. The focus feedback
given to the user is very subtle and easily overlooked. Also, the buddy
control and up-down button are normally paired into a single logical control.
For these reasons, you should not set the tab stop property for the up-down
control in most cases.
To set, validate, or retrieve the value of the edit control, use ClassWizard
to associate a CEdit object with the edit control or use one of
the other techniques discussed in Chapter 6, "Using Edit Controls."
DO/DON'T: DO associate a buddy control with the up-down control.
DO set a limit for the up-down control.
DO make the buddy control precede the up-down control in the
tab order.
DON'T set the tabstop property for the up-down control.
Using the CSpinButtonCtrl Class
The MFC class CSpinButtonCtrl can be used to manage an up-down
control. Use ClassWizard to associate the IDC_SPIN control with
a CSpinButtonCtrl object, using the values from Table 16.2.
Table 16.2. Values used to add a CSpinButtonCtrl
member variable for CControlsDlg.
Control ID
Variable Name
Category
Type
IDC_SPIN
m_spin
Control
CSpinButtonCtrl
Changing the Behavior of the Up-Down Control
As discussed earlier, the default behavior for an up-down control is to
increment the control if the down arrow is clicked and decrement the control
if the up arrow is clicked. You can change this behavior by reversing the
range of the up-down control.
To change the range of an up-down control, use the CSpinButtonCtrl's
SetRange function.
SetRange has two parameters: the first parameter is the lower-limit
value for the control, the second parameter is the upper limit:
m_spin.SetRange( 100, 0 );
To set a new range for the up-down control, add the source code from Listing
16.1 to the CControlsDlg::OnInitDialog member function. This source
code should be added just after the // TODO comment.
TYPE: Listing 16.1. Setting the range for an up-down
control.
// TODO: Add extra initialization here
m_spin.SetRange( 0, 100 ); Compile and execute
the Controls project. The up-down control increments the edit control when
its up arrow is clicked and decrements the edit control when the down arrow
is clicked.
Using the Slider Control
New Term: A slider control,
also known as a trackbar control, is a control that contains a slide bar
that you can move between two points. A slider is used in the Display applet
that is part of the Windows Control Panel. The Settings property page uses
a slider to set the screen resolution.
The user moves the slide bar by dragging it with the mouse or by setting
the keyboard focus to the slider and using the arrow keys on the keyboard.
You can create sliders with optional tick marks that help the user to judge
the position of the slide bar.
Deciding When to Use a Slider Control
Sliders are useful when a user is asked to select a value within a certain
range. A slider gives the user immediate feedback about the control's current
value, as well as the value's relationship to the high and low ranges.
Sliders are added to dialog boxes just like other controls; just drag
and drop the control from the controls palette to the dialog box. Although
you can create a slider from scratch, it's much easier to add one in the
Developer Studio dialog box editor.
Open the IDD_CONTROLS_DIALOG resource and add a slider control
by dragging a slider control from the control palette and dropping it on
the dialog box. Figure 16.2 shows the Controls dialog box after you add
the slider control.
figure 16.2 The main dialog box from the Controls project after you add a slider.
Open the properties dialog box for the slider control and change the
resource ID to IDC_SLIDER. All other properties can remain set
to their default values for now. In the next section, you learn about the
properties offered for slider controls.
Slider Control Properties
The Properties dialog box for a slider control contains many of the same
options offered for up-down controls, as well as a few that are exclusive
to slider controls. The available options include the following:
ID is used for the slider's resource ID. A default resource ID,
such as IDC_SLIDER1, is supplied by Developer Studio.
Visible is used to indicate that the control is initially visible.
This check box is usually checked.
Disabled is used to indicate the control should be initially disabled.
This check box is usually cleared.
Group is used to mark the first control in a group. This check box
is usually cleared.
Tab Stop indicates that this control can be reached by pressing
Tab on the keyboard. This check box is usually checked.
Help ID indicates that a context-sensitive help ID should be generated
for this control.
Orientation is used to specify if the slider is vertical or horizontal.
The default value is vertical.
Point is used to indicate the position of optional tick marks. There
are three options: Top/Left, Bottom/Right, or Both. The default value is
Bottom/Right.
Tick Marks indicates that tick marks should be drawn for the slider.
This check box is usually cleared.
Auto Ticks indicates that tick marks should be drawn at intervals
along the slider control. This option check box is usually cleared.
Enable Selection enables the slider to be used to select a range
of values. This check box is usually cleared.
Border is used to specify that a border should be drawn around the
control. This check box is usually checked.
In the next section, you use a slider to control a progress control. To
prepare for that example, open the properties dialog box and make sure
the following slider properties are selected:
Tick Marks
Auto Ticks
Enable Selection
Using the Progress Control
A progress control, also known as a progress bar, is commonly used to indicate
the progress of an operation and is usually filled from left to right as
the operation is completed. You can also use progress controls to indicate
temperature, water level, or similar measurements. In fact, an early term
for this type of control was "Gas Gauge," back in the old days when programmers
had mules and most Windows programs were written in C.
Progress controls are used in Developer Studio to indicate the progress
of saving or loading a project workspace. The Windows Explorer also uses
progress controls when copying or moving files.
Just a Minute: Progress
controls are an easy way to give feedback to the user about the status
of a task. Instead of waiting an unknown length of time, the user can see
what portion of a job has yet to be completed.
A progress control is added to a dialog box in the same way as the up-down
and slider controls discussed earlier. Using the Developer Studio dialog
box editor, add a progress control to the Controls project main dialog
box. Figure 16.3 shows the main dialog box from the Controls project after
the progress control has been added.
figure 16.3
The Controls dialog box after adding the progress control.
After you add the control, open the properties dialog box and change
the resource ID to IDC_PROGRESS. A progress control doesn't have
optional properties other than those available on all controls:
ID is used for the progress control's resource ID. A default resource
ID, such as IDC_PROGRESS1, is supplied by Developer Studio.
Visible is used to indicate that the control is initially visible.
This check box is usually checked.
Disabled is used to indicate the control should be initially disabled.
This check box is usually cleared.
Group is used to mark the first control in a group. This check box
is usually cleared.
Tab Stop indicates that this control can be reached by pressing
Tab on the keyboard. This check box is usually checked.
Help ID indicates that a context-sensitive help ID should be generated
for this control.
Border is used to specify that a border should be drawn around the
control. This check box is usually checked.
For this example, you can set the progress control properties to their
default values.
Using a Slider to Update a Progress Control
In this section, you use the IDC_SLIDER slider control to change
the value displayed by the progress control. Using ClassWizard, add two
new member variables associated with the slider and progress controls to
the
CControlsDlg class. Use the values from Table 16.3 for the
new controls.
Table 16.3. Values for slider and progress control
member variables.
Control ID
Variable Name
Category
Type
IDC_SLIDER
m_slider
Control
CSliderCtrl
IDC_PROGRESS
m_progress
Control
CProgressCtrl
Initializing the Slider and Progress Controls
The slider and progress controls must be initialized before you can use
them. The CProgressCtrl and
CSliderCtrl classes each
provide a SetRange function that is used to set minimum and maximum
values for their respective controls.
m_slider.SetRange( 0, 100 );
The slider also enables tick marks to be placed along the slider control
if the Autoticks check box has been selected. Use the SetTicFreq
function to specify the distance between each tick mark. To add tick marks
every 10 positions, pass a value of 10 to SetTicFreq.
m_slider.SetTicFreq( 10 );
Listing 16.2 contains new source code for the initialization section of
OnInitDialog. Add this source code just after the // TODO
comment.
TYPE: Listing 16.2. Initializing the controls in
CControlsDlg::OnInitDialog.
// TODO: Add extra initialization here
m_spin.SetRange( 0, 100 );
m_slider.SetRange( 0, 100 );
m_slider.SetTicFreq( 10 );
m_progress.SetRange( 0, 100 );
Handling Messages from the Slider to the Progress
Control
When a slider is moved, it notifies its parent using WM_SCROLL
and WM_HSCROLL messages. Because the slider in this example is
a horizontal slider, it sends WM_HSCROLL messages to the main
dialog box. Using ClassWizard, add a message-handling function to the CControlsDlg
class for the WM_HSCROLL message. The source code for the OnHScroll
function is provided in Listing 16.3.
TYPE: Listing 16.3. Using slider scroll messages
to update the progress control.
} The code in Listing 16.3 is called whenever
the trackbar position is changed. The
CSliderCtrl::GetPos function
is used to collect the current slider position, which is then used to update
the progress control using the CProgressCtrl::SetPos function.
Just a Minute: There are
many ways to use the progress control. Many times, you will update the
progress control after receiving events that you don't have direct control
over. For example, when copying a large number of files, your program might
update a progress control after copying each file. During an installation,
you might want to update a progress control after each phase of the installation
is complete.
Compile and run the Controls project. You can adjust the value displayed
in the progress control by moving the slider control. The completed project
is shown in Figure 16.4.
figure 16.4
The finished Controls project.
Summary
In this section, you looked at up-down, slider, and progress controls,
three of the simpler controls offered by Windows. You examined the uses
for each control and the MFC classes used to interact with them and created
a small dialog box-based project that used all three controls.
Q&A
Q The up-down control is paired with the wrong control when I run my
program--what's wrong?
A The up-down control must immediately follow the buddy control
in the tab order. If the tab order isn't set correctly, the up-down control
will latch on to whatever control precedes it. When you are working with
your dialog box in Developer Studio, press Ctrl+D to see the tab order.
Q Is there an easy way to increase the value displayed in the progress
control by a specific amount, rather than setting a new value?
The Workshop is designed to help you anticipate possible questions, review
what you've learned, and begin thinking ahead to putting your knowledge
into practice. The answers to the quiz are in Appendix B, "Quiz Answers."
Quiz
1. What property is used to change the up-down control arrows to left-right
instead of up-down?
2. What property is used to indicate that the up-down control is associated
with a buddy control?
3. What function is used to set the limits of the up-down control?
4. How do you specify which control is the buddy control?
5. What property is used to add division lines on the slider control?
6. What function is used to set the limits of the slider control?
7. What function is used to set the limits of the progress control?
Exercises
1. Change the Controls project so that the value of the up-down control
controls the progress control.
2. Experiment with changing the up-down control's alignment and orientation
from right to left, and from vertical to horizontal.