As a Windows user, you've long been accustomed to seeing controls like buttons, list boxes, menus, and edit boxes. As Windows developed, however, Microsoft noticed that applications developers routinely created other types of controls in their programs. These controls included things like toolbars, status bars, progress bars, tree views, and others. To make life easier for Windows programmers, when Microsoft created Windows 95 (and the latest version of Windows NT), it included these popular controls as part of the operating environment. Now, Windows programmers no longer need to create their own versions of these controls from scratch. In this chapter, you'll be introduced to several of Windows 95's common controls.
Over the course of the next few chapters, you build a sample program called Win95 Controls App. You can find the program's executable file, as well as the complete source code, in the CHAP09 folder at this book's Web site. When you run the program, you see the window shown in Figure 9.1. As you can see, Win95 Controls App demonstrates five of the Windows 95 common controls: the progress bar, slider, spinner, list view, and tree view controls. In this chapter, you'll learn the basics of creating and using three of these controls.
The Windows 95 Controls App demonstrates five of Windows 95's common controls.
To get going quickly, you'll start creating the Win95 Controls application using AppWizard. Then you'll learn how to use MFC to create and manipulate the Windows 95 controls demonstrated by the application. To build the basic Win95 Controls application, follow the steps given next.
ON THE WEB
http://www.quecorp.com/semfc The complete source code and executable file for this part of the Win95 application can be found in the CHAP09\Win95, Part 1 directory at this book's Web site.
Step 1 | Single document. |
Step 2 of 6 | Use default options. |
Step 3 of 6 | Use default options. |
Step 4 of 6 | Turn off everything except 3D Controls. |
Step 5 of 6 | Use default options. Step 6 of 6Use default classes. |
cs.cx = 480; cs.cy = 440;
These lines set the size of the application's main window.
You have now completed the first part of the Win95 Controls App. Compile and link the application by selecting the Build button in the toolbar; by selecting
Developer Studio's Build, Build command; or by pressing F7. When you have the program compiled, you can run it if you like. However, all you'll
see at this point is a blank window, as shown in Figure 9.11. In the following sections in this chapter, you'll add several Windows 95 common controls to the
application, starting with the progress bar control. In the next chapter, you'll complete the application.
This is the basic Win95 Controls App, before any controls have been added.
Probably the easiest to use of the new common controls is the progress bar, which is nothing more than a rectangle that fills in slowly with colored blocks. The more colored blocks filled in, the closer to complete a task is. When the progress bar is completely filled in, the task associated with the progress bar is also complete. You might use a progress bar to show the status of a sorting operation or to give the user visual feedback about a large file that's being loaded.
To add the progress bar to the Win95 Controls App application, follow these steps.
ON THE WEB
http://www.quecorp.com/semfc The complete source code and executable file for this part of the Win95 application can be found in the CHAP09\Win95, Part 2 directory at this book's Web site.
Listing 9.1[em]LST09_01.CPP[md]The CreateProgressBar() Function
void CWin95View::CreateProgressBar() { m_progressBar.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(20, 40, 250, 80), this, 102); m_progressBar.SetRange(1, 100); m_progressBar.SetStep(10); m_progressBar.SetPos(50); m_timer = FALSE; }
pDC->TextOut(20, 22, "Progress Bar Control");
Listing 9.2[em]LST09_02.CPP[md]Code for the OnLButtonDown() Function
if (m_timer) { KillTimer(1); m_timer = FALSE; } else { SetTimer(1, 500, NULL); m_timer = TRUE; }
KillTimer(1);
protected: CProgressCtrl m_progressBar; BOOL m_timer;
void CreateProgressBar();
You have now completed the second part of the Win95 Controls App. Compile and link the application by selecting the Build button in the toolbar; by selecting
Developer Studio's Build, Build command; or by pressing F7. When you run the application now, you see the window shown in Figure 9.16.
The Win95 Controls App now sports a snazzy progress bar.
To see the progress bar in action, click anywhere in the background of Win95 Controls App's window. When you do, the progress bar starts filling with colored blocks. When the progress bar is completely filled, it starts over again. This continues until you click the window again or exit the program. Of course, in this program, the progress bar isn't tracking a real task in progress. It's simply responding to timer messages. However, the program still demonstrates how you might use a progress bar in your own applications.
This might be an obvious statement, but before you can use a progress bar, you must create it. Often in an MFC program, the controls are created as part of a dialog box. However, Win95 Controls App displays its controls in the application's main window. It does this by creating controls in the view class's OnCreate() function, which responds to the WM_CREATE Windows message. The progress bar control is declared as a data member of the view class, like this:
protected: CProgressCtrl m_progressBar;
As you can see, the progress bar is an object of the MFC CProgressCtrl class.
To create the progress bar control, OnCreate() calls the local CreateProgressBar() member function, like this:
CreateProgressBar();
In CreateProgressBar() is where the fun begins. First, the function creates the progress bar control by calling the control's Create() function:
m_progressBar.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(20, 40, 250, 80), this, 102);
This function's four arguments are the control's style flags, the control's size (as a CRect object), a pointer to the control's parent window, and the control's ID. (Usually, you declare a constant, such as IDC_PROGRESSBAR, to use as the control's ID. I used a hard-coded value to keep the code as simple as possible.) The style constants are the same constants you would use for creating any type of window (a control is really nothing more than a special kind of window, after all). In this case, you need at least WS_CHILD (which indicates that the control is a child window) and WS_VISIBLE (which ensures that the user can see the control). The WS_BORDER style is a nice addition, because it adds a dark border around the control, setting it off from the rest of the window.
As soon as the progress bar control is created, it must be initialized. The CProgressCtrl class features a number of member functions that enable you to initialize and manipulate the control. Those member functions and their descriptions are listed in Table 9.1.
Table 9.1 Member Functions of the CProgressCtrl Class
Function | Description |
Create() | Creates the progress bar control |
OffsetPos() | Advances the control the given number of blocks |
SetPos() | Sets the control's current value |
SetRange() | Sets the control's minimum and maximum values |
SetStep() | Sets the value by which the control advances |
StepIt() | Advances the control by one step unit |
To initialize the control, you merely call the CProgressCtrl object's appropriate member functions, which Win95 Controls App does like this:
m_progressBar.SetRange(1, 100); m_progressBar.SetStep(10); m_progressBar.SetPos(50);
The call to SetRange() determines the values represented by the progress bar. The two arguments are the minimum and maximum values. So, after the preceding call to SetRange(), if the progress bar is set to 1, it displays no colored blocks; in contrast, setting the control's position to 100 fills the control with colored blocks.
Next, the CreateProgressBar() function calls SetStep(), which determines how far the progress bar advances with each increment. The larger this value, the faster the progress bar fills with colored blocks. Because the range and the step rate are related, a control with a range of 1[nd]10 and a step rate of 1 works almost identically to a control with a range of 1[nd]100 and a step rate of 10.
When the Win95 Controls App starts, the progress bar is already half filled with colored blocks. (This is purely for aesthetic reasons. Usually a progress bar begins its life empty.) This is because of the call to SetPos() with the value of 50, which is the midpoint of the control's range.
In Win95 Controls App, the progress bar starts counting forward when you click in the window's background. This is because the program responds to the mouse click by starting a timer that sends WM_TIMER messages to the program twice a second. In the view class's OnTimer() function, the program makes the following function call:
m_progressBar.StepIt();
The StepIt() function increments the progress bar control's value by the step rate, causing new blocks to be displayed in the control as the control's value setting counts upward. When the control reaches its maximum, it automatically starts over.
Notice that there are no CProgressCtrl member functions that control the size or number of blocks that will fit into the control. This attribute is controlled indirectly by the size of the control.
Many times in a program, the user might have enter a value that lies within a specific range. For this sort of task, you'd use MFC's CSliderCtrl class to create a slider (sometimes called a trackbar) control. For example, suppose you need the user to enter a percentage that your program needs to calculate another value. In that case, you'd want the user to enter only values in the range from 0 to 100. Other values would be invalid and could cause problems in your program if such invalid values were not carefully trapped.
Using the slider control, you can force the user to enter a value in the specified range. Although the user can accidentally enter a wrong value (a value that doesn't accomplish what the user wants to do), he or she can't enter an invalid value (one that brings your program crashing down like a stone wall in an earthquake).
In the case of a percentage, you'd create a slider control with a minimum value of 0 and a maximum value of 100. Moreover, to make the control easier to position, you'd want to place tick marks at each setting that's a multiple of 10, giving 11 tick marks in all (including the one at 0). Win95 Controls App creates exactly this type of slider. The following steps show you how to add the control to Win95 Controls App.
ON THE WEB
http://www.quecorp.com/semfc The complete source code and executable file for this part of the Win95 application can be found in the CHAP09\Win95, Part 3 directory at this book's Web site.
pDC->TextOut(270, 22, "Slider Control:");
CreateSlider();
Listing 9.3 LST09_03.CPP The CreateSlider() Function
void CWin95View::CreateSlider() { m_slider.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | TBS_AUTOTICKS | TBS_BOTH | TBS_HORZ, CRect(270, 40, 450, 80), this, 101); m_slider.SetRange(0, 100, TRUE); m_slider.SetTicFreq(10); m_slider.SetLineSize(1); m_slider.SetPageSize(10); }
Listing 9.4 LST09_04.CPP Code for the OnHScroll() Function
CSliderCtrl* slider = (CSliderCtrl*)pScrollBar; int position = slider->GetPos(); char s[10]; wsprintf(s, "%d ", position); CClientDC clientDC(this); clientDC.TextOut(390, 22, s);
CSliderCtrl m_slider;
void CreateSlider();
You have now completed the third part of the Win95 Controls App. Compile and link the application by selecting the Build button in the toolbar; by selecting
Developer Studio's Build, Build command; or by pressing F7. When you run the application now, you see the window shown in Figure 9.18.
The Win95 Controls App now has a slider control, as well as a progress bar control.
To see the slider work, click on the slider's slot. When you do, the slider moves forward or backward, and the selected value appears to the right of the control's caption. As soon as the slider has the focus, you can also control it with your keyboard's Up Arrow and Down Arrow keys, as well as with the Page Up and Page Down keys. You can also drag the slider with your mouse to whatever position you like.
In the Win95 Controls App application, the slider is created in the CreateSlider() local member function, which, like CreateProgressBar(), the program calls from the view class's OnCreate() function. In CreateSlider(), the program first creates the slider control by calling its Create() member function, like this:
m_slider.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | TBS_AUTOTICKS | TBS_BOTH | TBS_HORZ, CRect(270, 40, 450, 80), this, 101);
This function's four arguments are the control's style flags, the control's size (as a CRect object), a pointer to the control's parent window, and the control's ID. The style constants include the same constants that you would use for creating any type of window, with the addition of special styles used with sliders. Table 9.2 lists these special styles.
Table 9.2 Slider Styles
Style | Description |
TBS_AUTOTICKS | Enables the slider to automatically draw its tick marks |
TBS_BOTH | Draws tick marks on both slides of the slider |
TBS_BOTTOM | Draws tick marks on the bottom of a horizontal slider |
TBS_ENABLESELRANGE | Enables a slider to display a subrange of values |
TBS_HORZ | Draws the slider horizontally |
TBS_LEFT | Draws tick marks on the left side of a vertical slider |
TBS_NOTICKS | Draws a slider with no tick marks |
TBS_RIGHT | Draws tick marks on the right side of a vertical slider |
TBS_TOP | Draws tick marks on the top of a horizontal slider |
TBS_VERT | Draws a vertical slider |
As soon as the slider control is created, it must be initialized. The CSliderCtrl class features many member functions that enable you to initialize and manipulate the control. Those member functions and their descriptions are listed in Table 9.3.
Table 9.3 Member Functions of the CSliderCtrl Class
Function | Description |
ClearSel() | Clears a selection from the control |
ClearTics() | Clears tick marks from the control |
Create() | Creates a slider control |
GetChannelRect() | Gets the size of the control's slider |
GetLineSize() | Gets the control's line size |
GetNumTics() | Gets the number of tick marks |
GetPageSize() | Gets the control's page size |
GetPos() | Gets the control's position |
GetRange() | Gets the control's minimum and maximum values |
GetRangeMax() | Gets the control's maximum value |
GetRangeMin() | Gets the control's minimum value |
GetSelection() | Gets the current range selection |
GetThumbRect() | Gets the size of the control's thumb |
GetTic() | Gets the position of a tick mark |
GetTicArray() | Gets all the control's tick positions |
GetTicPos() | Gets the client coordinates of a tick mark |
SetLineSize() | Sets the control's line size |
SetPageSize() | Sets the control's page size |
SetPos() | Sets the control's position |
SetRange() | Sets the control's minimum and maximum values |
SetRangeMax() | Sets the control's maximum value |
SetRangeMin() | Sets the control's minimum value |
SetSelection() | Sets a selected subrange in the control |
SetTic() | Sets the position of a tick mark |
SetTicFreq() | Sets the control's tick frequency |
VerifyPos() | Determines whether the control's position is valid |
Usually, when you create a slider control, you'll want to set the control's range and tick frequency. If the user is going to use the control from his or her keyboard, you also need to set the control's line and page size. In the Win95 Controls App application, the program initializes the slider as shown in Listing 9.5.
Listing 9.5 LST09_05.CPP Initializing the Slider Control
m_trackbar.SetRange(0, 100, TRUE); m_trackbar.SetTicFreq(10); m_trackbar.SetLineSize(1); m_trackbar.SetPageSize(10);
The call to SetRange() sets the slider's minimum and maximum values to 0 and 100, respectively. The arguments are the minimum value, the maximum value, and a Boolean value indicating whether the slider should redraw itself after setting the range. Next, the call to SetTicFreq() ensures that there will be a tick mark at each interval of 10. (Without this function call, the slider would have a tick mark for each possible setting, 101 in all.) Finally, the call to SetLineSize() determines how much the slider moves when the user presses his or her Up Arrow or Down Arrow keys, and the call to SetPageSize() determines how much the slider moves when the user presses the Page Up or Page Down keys.
When you get down to it, a slider is really a special scroll bar control. As such, when the user moves the slider, the control generates WM_HSCROLL messages, which Win95 Controls App captures in its view class's OnHScroll() member function, shown in Listing 9.6.
Listing 9.6 LST09_06.CPP Responding to a Slider Contro
void CWin95View::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default CSliderCtrl* slider = (CSliderCtrl*)pScrollBar; int position = slider->GetPos(); char s[10]; wsprintf(s, "%d ", position); CClientDC clientDC(this); clientDC.TextOut(390, 22, s); CView::OnHScroll(nSBCode, nPos, pScrollBar); }
OnHScroll()'s fourth parameter is a pointer to the scroll object that generated the WM_HSCROLL message. The preceding function first casts this pointer to the CSliderCtrl pointer. It then gets the current position of the slider by calling the CSliderCtrl member function GetPos(). As soon as the program has the slider's position, it converts the integer to a string and displays that string in the window.
The slider control isn't the only way you can get a value in a predetermined range from the user. If you don't care about using the slider for visual feedback, you can use a spinner control, which is little more than a couple of arrows that the user clicks to raise or lower the control's setting. If the slider control is a scroller with only a bar and a thumb, then a spinner control is the leftover arrow buttons. Follow the steps that come next to add a spinner control to Win95 Controls App.
ON THE WEB
http://www.quecorp.com/semfc The complete source code and executable file for this part of the Win95 application can be found in the CHAP09\Win95, Part 4 directory at this book's Web site.
pDC->TextOut(20, 102, "Spinner Control");
CreateSpinner();
Listing 9.7 LST09_07.CPP The CreateSpinner() Function
void CWin95View::CreateSpinner() { m_buddyEdit.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(50, 120, 110, 160), this, 103); m_spinner.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_ARROWKEYS, CRect(0, 0, 0, 0), this, 104); m_spinner.SetBuddy(&m_buddyEdit); m_spinner.SetRange(1, 100); m_spinner.SetPos(50); }
CSpinButtonCtrl m_spinner; CEdit m_buddyEdit;
void CreateSpinner();
You have now completed the fourth part of the Win95 Controls App. Compile and link the application by selecting the Build button in the toolbar; by selecting
Developer Studio's Build, Build command; or by pressing F7. When you run the application now, you see the window shown in Figure 9.19.
This version of Win95 Controls App adds a spinner to the other controls.
In the Win95 Controls App application, you can change the setting of the spinner control by clicking either of its arrows. When you do, the value in the attached edit box changes, indicating the spinner control's current setting. As soon as the control has the focus, you can also change its value by pressing your keyboard's Up Arrow and Down Arrow keys.
In the Win95 Controls App application, the spinner control is created in the CreateSpinner() local member function, which the program calls from the view class's OnCreate() function. In CreateSpinner(), the program creates the spinner control by first creating the associated buddy control to which the spinner control communicates its current value. In this case, as is typical, the buddy control is an edit box, which is created by calling the CEdit class's Create() member function:
m_buddyEdit.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(50, 120, 110, 160), this, 103);
This function's four arguments are the control's style flags, the control's size, a pointer to the control's parent window, and the control's ID. As you might remember from the control declarations, m_buddyEdit is an object of the CEdit class.
Now that the program has created the buddy control, it can create the spinner control in much the same way, by calling the object's Create() member function, like this:
m_spinner.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | UDS_ALIGNRIGHT | UDS_SETBUDDYINT | UDS_ARROWKEYS, CRect(0, 0, 0, 0), this, 104);
As you can guess by now, this function's four arguments are the control's style flags, the control's size, a pointer to the control's parent window, and the control's ID. As with most controls, the style constants include the same constants that you would use for creating any type of window. However, the CSpinButtonCtrl class, of which m_spinner is an object, defines special styles to be used with spinner controls. Table 9.4 lists these special styles.
Table 9.4 Spinner Styles
Style | Description |
UDS_ALIGNLEFT | Places the spinner control on the left edge of the buddy control |
UDS_ALIGNRIGHT | Places the spinner control on the right edge of the buddy control |
UDS_ARROWKEYS | Enables the user to change the control's values using the keyboard's Up Arrow and Down Arrow keys |
UDS_AUTOBUDDY | Makes the previous window the buddy control |
UDS_HORZ | Creates a horizontal spinner control |
UDS_NOTHOUSANDS | Eliminates separators between each set of three digits |
UDS_SETBUDDYINT | Displays the control's value in the buddy control |
UDS_WRAP | Causes the control's value to wrap around to its minimum when the maximum is reached and vice versa |
As soon as the spinner control is created, it must be initialized. The CSpinButtonCtrl class features member functions that enable you to initialize and manipulate the control. Those member functions and their descriptions are listed in Table 9.5.
Table 9.5 CSpinButtonCtrl Member Functions
Function | Description |
Create() | Creates the spinner control |
GetAccel() | Gets the control's speed |
GetBase() | Gets the control's numerical base |
GetBuddy() | Gets a pointer to the control's buddy control |
GetPos() | Gets the control's position |
GetRange() | Gets the control's minimum and maximum values |
SetAccel() | Sets the control's speed |
SetBase() | Sets the control's numerical base (10 for decimal, 16 for hex) |
SetBuddy() | Sets the control's buddy control |
SetPos() | Sets the control's position |
SetRange() | Sets the control's minimum and maximum values |
After creating a spinner control, you'll usually want to set the control's buddy, range, and position. In the Win95 Controls App application, the program initializes the control like this:
m_spinner.SetBuddy(&m_buddyEdit); m_spinner.SetRange(1, 100); m_spinner.SetPos(50);
Here, the spinner control's buddy is set to the edit box that was first created in CreateSpinner(). Then the program calls SetRange() and SetPos() to give the control its starting range and position, respectively. Thanks to the UDS_SETBUDDYINT flag passed to Create() and the call to the control's SetBuddy() member function, Win95 Controls App needs to do nothing else to have the control's value appear on the screen. The control handles its buddy automatically.