Platinum Edition Using Visual Basic 5

Previous chapterNext chapterContents


- 10 -
Using the Windows Common Controls

With a little bit of programming, you can make your toolbars respond to changes in your program.
A status bar allows you to inform users of program operations in a manner with which they are familiar.
When users run a task, they want to see action. A progress bar lets users know that a task is running and gives them an approximation of the time remaining until completion.
Make numerical input simple with the Slider control.
The TreeView and ListView controls provide the capability to implement Windows Explorer-style interfaces for working with lists.
The TabStrip control enables you to create multiple pages and allows your user to navigate among them.

Visual Basic includes a group of common controls that enable you to develop programs with many of the same features as programs from Microsoft and other vendors. These controls let you create toolbars to supplement your menus, status bars to keep your users informed, progress bars to indicate the completion level of a task, and other neat controls. This chapter continues the in-depth discussion of controls that began in Chapter 9, "Using the Windows Standard Controls," by covering the capabilities of the Windows Common Controls.

Working with the Windows Common Controls

To use the controls described in this chapter, you must first make them available in your Toolbox. From the Visual Basic menu, choose Project, Components. When the Components dialog box appears, place a check mark next to Microsoft Windows Common Controls 5.0 and click OK. Your Toolbox will then be updated with the new controls.

Creating Toolbars

Toolbars, such as the one shown in Figure 10.1, are an integral part of Windows interface standards, so much so that Microsoft has packaged them into the COMCTL32.OCX custom control. Applications that don't have toolbars are becoming the exception to the rule for an obvious reason: Toolbars provide a convenient place on-screen for users to look for frequently used functions. Because the toolbar is normally near the top of the window, it provides a familiar place for the user to look in almost any application.

FIG. 10.1
A Visual Basic program can include the Toolbar control.

The Toolbar control works with an ImageList control, which holds all the button images. Visual Basic includes a number of images in the Graphics subdirectory. Icon and bitmap files can be stored in an ImageList control; the size of these pictures will influence the size of the toolbar buttons. Before you can design an effective toolbar, you need to pick out your images and add them to an image list.

Reviewing the Basics

Toolbars were first discussed in Chapter 5, "Adding Menus and Toolbars to Your Program," in which you saw how toolbars were used to supplement the menus of a program by placing commonly used functions where the user could get to them easily.

The Toolbar control enables you to create five different types of buttons:

The ImageList control is used to hold the images that are placed on the toolbar buttons. The Toolbar and the ImageList controls can be set up through the Properties window and through the Property Pages of the controls.

See "Creating a Toolbar for Your Application," Chapter 5

Creating a Toolbar with Code

Although you can set up a toolbar in the design environment, you can also set up and change a toolbar at runtime with program code. To use the Toolbar and other common controls successfully, you need to understand the concept of collections.

Understanding Collections A collection is a group of objects. In the case of the ImageList control, there is a collection called ListImages. The objects stored in this particular collection are the images in the ImageList control. By manipulating the ListImages collection from code, you can add, remove, and change images. Think of a collection as being similar to, but not exactly like, an array. You can access it like an array, as in the following line of code, which sets a form's picture to the first image in an ImageList control:

Set form1.Picture = ImageList1.ListImages(1).Picture

Notice that a specific object is referred to with its index--in this case, 1. Remember, a collection stores objects, unlike an array, which stores values. These objects have their own set of properties.

One special property that objects in a collection have is the Key property. An object's key is a text string that can be used in the same manner as an index:

Set form1.Picture = ImageList1.ListImages("Smiley Face").Picture

Of course, you have to set the key first, usually when an object is added to a collection. Each type of collection has Add and Remove methods defined that include Key and Index as parameters. If omitted, the index is supplied by Visual Basic. The key, however, is optional.

Setting Up the Toolbar To set up a Toolbar control in code, you have to first set up an ImageList control (either in design mode or with code). Then, you can assign ImageList to the toolbar with the following statement:

Set ToolBar.ImageList = ImageList1

Next, you manipulate the toolbar's Buttons collection to create toolbar buttons. In the example below, a separator and standard button are added to a toolbar control, tbrMain:

tbrMain.Buttons.Add 1, "Sep1",, tbrSeparator, 0
tbrMain.Buttons.Add 2, "open","Open File" , tbrDefault, 1

In the example above, two additional Button objects are created in the Buttons collection by using the Add method. The first two parameters are the button's index and key, each of which must be unique. The third parameter is the button caption. The fourth parameter (tbrSeparator and tbrDefault) is a constant representing the type of button. Finally, an index value from the associated image list tells the toolbar which picture to use.

The Add method can also work as a function. If used in this manner, it returns a pointer to the Button object just created. The preceding code could be rewritten like this:

Dim btn As Button
Set btn = tbrMain.Buttons.Add(, "Sep1", , tbrSeparator, 0)
Set btn = tbrMain.Buttons.Add(,"open", , tbrDefault)
btn.ToolTipText = "Click to open a file"
btn.Caption = "Open File"
btn.Image = 1

Note that the ToolTipText property must be defined from a Button object because it is not in the Add method's parameters. Also, in the preceding example, the Index properties will be defined automatically because they were not specified. This is generally the preferred way of doing things because, as objects are added and deleted from a collection, the index of a particular object will change. The Key, however, will always be associated with a specific object.

Your code can use the Key to determine which button was pressed. For example, consider the following code in the toolbar's ButtonClick event:

Private Sub Toolbar1_ButtonClick(ByVal Button As ComctlLib.Button)
    Select Case Button.Key
        Case "open"
            `Insert open file code here
        Case "save"
            `Insert save file code here
        Case "exit" 
            `Insert code to end the program
    End Select
    
End Sub

The preceding code works great for buttons of type tbrDefault. However, if you have any tbrCheck buttons, you should have your code also check the Value property to see what the state of the button is:

        Case "boldface"
            If Button.value = tbrUnpressed then 
                `Button is "Up" - Turn bold off
            Else
                 `Button is "down" - Turn bold on
        End If

If you set the MixedState property of a button to True, it will always look grayed out--no matter what the value.

Monitoring the Status of Your Program

One of the most important aspects of any program is keeping the user informed about what is going on in the program at any given time. Users like to know whether a database is open, how many records there are in a set, and how many records have been processed so far in the current task. For a program such as a word processor, the users like to know what's the current page and what's the current position on that page. This type of information is called status information, which is usually displayed on-screen all the time, rather than in a message box.

Before the StatusBar control, Visual Basic programmers often used "fake" status bars made from panels and Label controls. These worked quite well (and still do today). However, the StatusBar control introduced in Visual Basic 4 provides a much better alternative. You don't have to worry about extra overhead, because it is likely that you probably already are using one of the other Common Controls in the same OCX.

Figure 10.2 shows a typical status bar from a Visual Basic program.

FIG. 10.2
Status bars display current information about a program.

Creating a Status Bar

You start the creation of the status bar by selecting the control and drawing it on your form. When it is first drawn, the status bar will span the width of its parent form and will contain a single panel, as shown in Figure 10.3. You will also notice that no matter where on your form you draw the status bar, it moves to the bottom of the form automatically. This is the typical location for a program's status bar.

FIG. 10.3
A status bar placed on a form is configured automatically.

After you have drawn the status bar, you are ready to start setting the properties to control its appearance and to create any additional panels that you will need for to display information. As you saw when you first drew the status bar control, it sizes itself to fit across the entire form. This is an automatic action, and you have no control over it. You can, however, control the height of the status bar either by setting its Height property or by clicking and dragging one of its sizing handles. Two other properties control the basic appearance of the entire status bar: the Align property and the Style property.

The Align property of the status bar controls which edge of the form, if any, the status bar is "docked" against. The Align property has five possible settings:


CAUTION: If you change the Align property of a status bar after placing it on a form, it may resize itself to fill the entire form. If this happens, you must change the Height or Width property from the Properties window.

Figure 10.3 showed how the status bar looked aligned at the bottom of the form. Top alignment and no alignment have a similar appearance.

Figure 10.4 shows how the status bar looks aligned at an edge of the form. Unless you have a specific reason for using a different alignment, it is best to stick with the default, bottom alignment. Although another alignment might be a novel approach, it would probably confuse users who are accustomed to the standard alignment.

FIG. 10.4
You can align a status bar at one of the edges of the form.

The other property that controls the overall appearance of the status bar is the Style property. This property has two settings that determine whether the status bar will display a single panel or multiple panels:

The effect of these two settings are shown in Figure 10.5.

FIG. 10.5
You can create either a single-panel or a multiple-panel status bar.

Working with the Panels of the Status Bar

The real work of the status bar is handled by its panels. Each panel is a separate object with its own properties that control its appearance and behavior. Each panel is part of the status bar's Panels collection. After you draw the status bar on your form and set its basic properties, you can begin adding panels to the bar. You do this through the Property Pages of the status bar. This dialog box, shown in Figure 10.6, is accessible by clicking the ellipsis button to the right of the Custom property in the Properties window.

FIG. 10.6
Property Pages let you manage the panels of your status bar.


TIP: You can also access the Property Pages by right-clicking the status bar to access the pop-up menu and then by choosing Properties from the menu.

Setting Up a Panel To set up an individual panel, you simply set its properties by using the Property Pages. Eight main properties control the appearance and behavior of the panel:

While most of these properties are self-explanatory, the Style and AutoSize properties merit further attention.

You can create seven different styles of panels for your status bar. While one of the styles is designed for you to display text, most styles are predefined status items. These styles display the settings of the lock keys (such as Caps Lock, Num Lock, and so on) or the system date and time. These styles are handled by the control itself, so you can set them up in design mode and then you don't have to do anything while the program is running. The styles of panels are summarized in Table 10.1 and are displayed in Figure 10.7.

Table 10.1 Panel Styles Are Available to Your Programs

Setting Description
sbrText Displays text or a bitmap. The text displayed is contained in the Text property of the panel, whereas the bitmap would be contained in the Picture property.
sbrCaps Handles the status of the Caps Lock key. This panel will display CAPS in bold letters when the key is on, and will display the letters dimmed when the key is off.
sbrNum Handles the status of the Num Lock key. This panel will display NUM in bold letters when the key is on, and will display the letters dimmed when the key is off.
sbrIns Handles the status of the Insert key. This panel will display INS in bold letters when the key is on, and will display the letters dimmed when the key is off.
sbrScrl Handles the status of the Scroll Lock key. This panel will display SCRL in bold letters when the key is on, and will display the letters dimmed when the key is off.
sbrTime Displays the current time.
sbrDate Displays the current date.


NOTE: An eighth setting, sbrKana, is also associated with the Scroll Lock key. It displays KANA in bold letters when the key is on, and dimmed letters when the key is off. The KANA indicator is a special setting for Katakana characters used in Japanese programs.

FIG. 10.7
Most panel styles automatically keep track of status information.

The AutoSize property has three settings that help determine the size of the panel in your program. The default setting, NoAutoSize, sets the size of the panel to the dimension specified in the MinWidth property, and this size will not change as other panels are added and removed. The sbrContents setting sets the size of the panel to fit the text that the panel contains, whether this is text entered by you or the text used for the key status and date/time panels. The final setting, sbrSpring, allows panels to stretch to fit the width of the status bar. This prevents any empty space from being present in the bar.


NOTE: No matter which setting you choose for the AutoSize property, a panel will not be made smaller than the dimension set by the MinWidth property.

One final property of note is the Bevel property. As stated above, this property determines whether and how the 3-D effects of the panel are displayed. There are three settings for the Bevel property: sbrNoBevel, which produces a flat panel; sbrInset (the default), which produces a panel that looks embedded in the status bar; and sbrRaised, which produces a raised panel. These three bevel styles are shown in Figure 10.8.

FIG. 10.8
You can create flat, inset, or raised panels.

Managing Your Panels You have seen how to set the properties of an individual panel, but you also need to know how to add and remove panels. Within the Property Pages, this is very easy. To add a new panel, you simply click the Insert Panel button on the Panel page. This sets up a blank set of properties for the new panel. To remove a panel, click the Remove Panel button. This instantly removes the panel from the status bar, without requesting verification. Finally, if you want to move from panel to panel, click the arrow buttons on the Panel page. The status bar also gives you the capability to add and remove panels from code. This is handled by the methods of the Panels collection. There are three methods of the Panels collection:

Listing 10.1 shows how to add a new date panel to the status bar and how to delete the first panel in the bar. This listing also uses the Count property of the Panels collection, which tells you how many panels are present in the status bar.

Listing 10.1 STATUS.FRM--Use the Methods of the Panels Collection to Manage Panels in Code

Dim NewIdx
StatusBar1.Panels.Add
NewIdx = StatusBar1.Panels.Count
With StatusBar1.Panels(NewIdx)
    .Style = sbrDate
    .Bevel = sbrRaised
    .ToolTipText = Format(Date, "Long Date")
End With
StatusBar1.Panels.Remove 1


NOTE: Unlike most other collections, the Panels collection starts with an index of 1 and the index values run up to the Count property.

Running the Status Bar from Code

Now that you know how to set up the status bar, you are ready to see how it is used in code. You have seen that the key status and date/time panels handle their tasks automatically. These things are great, but the real power of the status bar is its capability to change the text that appears in the text-style panel(s) as your program is running. These text panels tell the user the actual status of operations in your program.

To update the status of an item in your program, you assign a text string to the Text property of the Panel object, as shown in the following line of code:


StatusBar1.Panels(1).Text = "Viewing record 1 of 10"

You can, of course, set other properties of the panels the same way. You can even set up your entire status bar from code by using the methods of the Panels collection and the properties of the Panel objects. As an example, Listing 10.2 shows how to set up the status bar shown in Figure 10.9.

FIG. 10.9
Control your status bar by setting the properties of the Panel objects.

Listing 10.2 STATUS.FRM--You Can Set Up Your Entire Status Bar from Code

Private Sub Form_Load()
With StatusBar1
    .Panels(1).AutoSize = sbrSpring
    .Panels(1).Text = "Ready"
    .Panels.Add
    .Panels(2).Style = sbrCaps
    .Panels(2).AutoSize = sbrContents
    .Panels(2).MinWidth = 100
End With
End Sub


TIP: As with the Toolbar control, you also can reference a specific panel with its key:
sbrMain.Panels("page").Text = "Page 1 of 14"

For some of the status messages in your program, you will need more space than is available in one of the text panels. In this case, you can switch the style of the status bar from normal to simple. This gives you the full width of the status bar in which to display the message. To show the message you will need to set the SimpleText property. After the user has responded to the message or moved the mouse to another area, you can change the status bar back to normal style. This technique is shown in Listing 10.3.

Listing 10.3 STATUS.FRM--Change the Style of the Status Bar to Display Long Messages

Dim StatText As String
StatusBar1.Style = sbrSimple
StatText = "No database is open yet. You cannot access "
StatText = StatText & "any records at this point."
StatusBar1.SimpleText = StatText
`To return the status bar to normal -
StatusBar1.Style = sbrNormal

Keeping Tabs on Your Progress

Although the status bar is the primary means for you to keep users informed about what is going on in your program, it is not the only control that you can use to monitor progress in your program. Many programs have some tasks that take a relatively long time, and you'll want the capability to provide users with a dynamic indication of the operation's progress. The ProgressBar control is ideal for this situation. For example, Microsoft Internet Explorer uses a progress bar to indicate the percentage completed of a file transfer operation. In this case, the progress bar lets you know two things: First, as long as the bar is changing, you know that the file transfer is progressing. Second, by looking at the progress bar, you have some idea how much time is left in the transfer operation.

Setting Up the Progress Bar

The ProgressBar control is very easy to set up and use. As with other controls, you first draw the bar on your form. Then you will need to set the bar's properties. Among the several properties that can influence the look of the progress bar, Height and Width are the key properties. A progress bar typically is many times wider than it is tall. In fact, Microsoft recommends (in the Help system) that you make the width of the bar at least 12 times the height. Figure 10.10 shows a typical progress bar.

FIG. 10.10
Progress bars let the user know how much of an operation has been performed.

The Value property of the progress bar sets or retrieves how much of the progress bar appears filled in. If you compare a ProgressBar control to a thermometer, the Value property is like the temperature. Everything below the current temperature is filled with mercury, while the remaining area is blank.

Max and Min are the other properties that you need to set for the progress bar. These represent the maximum and minimum values allowed for the Value property. In the case of the thermometer, they represent the top and bottom of the temperature scale. For example, if you set the Min property to 0 and the Max property to 100, setting the Value property to 50 causes the progress bar to look half-full.

The setting of the Max and Min properties can be any valid integer, although the Max property must always be greater than the Min property. You can set these properties to any values that make sense for your applications. Some examples might be:

Updating the Progress Bar as Your Code Runs

The key to displaying the progress of an operation in the progress bar is setting the Value property. As your code runs through an operation, you periodically update the Value property's setting. As you might expect, you often do this in a loop that is performing a repetitive operation. Listing 10.4 shows how this is done for a long database operation.

Listing 10.4 Setting the Value Property to Show Actual Progress

`In the following code, "rsMain" is a recordset
`that has already been opened and populated.
`"pbr" is the ProgressBar control.
pbr.Min = 0rsMain.MoveLast
pbr.Max = rsMain.RecordCount
rsMain.MoveFirst  inCounter = 0
While Not rsMain.EOF
`Insert code to process record here
     inCounter = inCounter + 1
     pbr.Value = inCounter
     rsMain.MoveNext
Wend

Sliding into Numbers

Another Windows Common Control is the Slider control. The Slider control provides another means for the user to enter numeric data into a program. The slider works like the slider switches you might find on your stereo system's graphic equalizer or in a manner similar to the scroll bars that you have in the standard control set of Visual Basic. However, the slider has one advantage over the scroll bars. With the slider, you can also select a range of values, not just a single value by specifying minimum and maximum desired values.

Setting Up the Slider Control

You start creating the slider by drawing it on your form. There then are four main properties that control the appearance of the slider. These properties are summarized in Table 10.2. The effects of these properties are shown in Figure 10.11.

FIG. 10.11
The slider lets you select numeric information.

Table 10.2 Properties of the Slider Control

Property Settings
BorderStyle Set to 0 for no border or 1 for a single line border.
Orientation Set this property to 0 for a horizontal slider or 1 for a vertical slider.
TickStyle This property controls the placement of the tick marks on the slider. Set this to 0 to display tick marks below or to the right of the slider, set it to 1 to place tick marks above or to the left of the slider, set it to 2 to place tick marks on both sides, or set it to 3 to show no tick marks.
TickFrequency Determines how many tick marks are displayed. This can be set to any positive number.

After you have set up the appearance of the slider, you will need to set several properties that control its operation. The first two properties are the Min and Max properties, which control the range of values that can be handled by the slider control. The other two properties are the LargeChange and SmallChange properties. The LargeChange property controls how much the value of the slider will change if the user presses the Page Up or Page Down keys or clicks the mouse to either side of the slide bar. The SmallChange property controls how much the value of the slider will change if the user presses the right or left arrow keys. SelectRange is the final property affecting the operation of the slider. This property determines whether the slider can select only a single value or possibly select a range of values.

Using the Slider Control

When your users encounter the Slider control in your program, they can click the slide bar and drag it to set a value. They can also use the Page Up, Page Down, and right and left arrow keys to change the value. The information entered by the user is contained in the Value property of the slider.


NOTE: The keyboard keys work on a Slider control only if it has the focus.

If the SelectRange property is set to True, the user also can select a range of values by holding down Shift while clicking and dragging the slider bar. Unfortunately, this technique is not automatic; it must be managed by your code. You'll need to add code to the slider's MouseDown event procedure to determine whether the user has held down Shift while dragging the slider. If so, your code can set the slider's SelStart property, which defines the starting value of the range, and the SelLength property, which defines the extent of the range. Visual Basic's help system contains a very good example under the topic "SelLength, SelStart Properties (Slider control)."

Creating a Project with the Slider Control

To really demonstrate the use of the Slider control, you now will build a "color blender" project that uses an array of Slider controls to set the BackColor property of a form.

Setting Up the Interface of the Project To create the color blender, start a new project in Visual Basic and save it as ColorBld.Vbp. Next, rename the form to frmBlend and save it as frmBlend.Frm.


NOTE: At this point, you need to add the Windows Common Controls to the Toolbox, if they are not already present (refer to "Working with the Windows Common Controls" earlier in this chapter). Now you can start creating the interface of the program by adding controls.

Follow these steps to add the controls for the color blender project:

1. Place a check box on the form and name it ckGray. Set the Caption property of the check box to Only Shades Of Gray.

2. Place a Slider control on the form and name it sldColor.

3. Place a label on the form to the left of the slider and name it lblColor.

4. Make a set of control arrays for lblColor and sldColor. To do this, hold down the Ctrl key and click both lblColor and sldColor. Go to the Edit menu and click Copy. Paste the copied controls onto the form. You will be presented with a dialog box asking if you want to create a control array. Click Yes.

5. Add a third element to each control array by choosing Paste again.

6. Using the Properties window, set the caption of lblColor(0) to Red:, the caption of lblColor(1) to Green:, and lblColor(2) to Blue:.

7. Place the lblColor() and sldColor() control arrays as shown in Figure 10.12.

FIG. 10.12
The main form of the color blender project contains an array of Slider controls.

Setting Up the Code of the Project After you set up the interface of the program, you need to add some code to a couple of events to make the program work. The first event is the Load event of the form, which sets the initial condition of the program. The code for the Load event is shown in Listing 10.5.

Listing 10.5 COLORBLD.VBP--Initialize the Program in the Load Event of the Form

Private Sub Form_Load()
     Dim nCount As Integer
    Dim lRed As Long, lGreen As Long, lBlue As Long 
`Set up the sliders 
    For Count = 0 To 2
        sldColor(nCount ).Min = 0 
        sldColor(nCount ).Max = 255 
        sldColor(nCount ).TickFrequency = 4
   Next Count
    
    `Initialize the color of the form 
    `control. (This will set the color to black. RGB(0,0,0))
    frmBlend.BackColor = RGB(lRed, lGreen, lBlue)
    
End Sub

Next, you will need to add the code that actually changes the colors in response to movements of the Slider control. This code will be placed in the Scroll event of the Slider controls. The code is shown in Listing 10.6.

Listing 10.6 COLORBLD.VBP--Moving the Slider Changes the Color in the Color Blender

Private Sub sldColor_Scroll(Index As Integer)
    Dim nCount As Integer
    Dim lRed As Long, lGreen As Long, lBlue As Long 
     `Gray is equal values of Red, Green and Blue
    If ckGray Then
        `move all the sliders
                 For nCount = 0 to 2
             sldColor(nCount).Value = sldColor(Index).Value        
 Next nCount
    End If
    
    `Set the RGB value
    lRed = sldColor(0).Value
    lGreen = sldColor(1).Value
    lBlue = sldColor(2).Value
    
    `Assign the resultant RGB value to the backcolor
    frmBlend.BackColor = RGB(lRed, lGreen, lBlue)
 End Sub

Running the Project After you have entered the code, you are ready to run the program. Click the Start button or press F5 to compile and run the program. Then try setting different combinations of the color sliders to see the effect on the color blender. The ColorBld.Vbp project works like this: After an initialization process in the Form_Load event, most of the work takes place in the sldColor_Scroll event. As the user moves a slider from the array of Slider controls, the moved slider's index is passed into the sldColor_Scroll event. The application checks the value of the ckGray check box. If it is checked (True), the value of the moved slider is assigned to all the controls in the slider control array. This causes all the sliders to move to the same position before any other code is executed.

The application then assigns the value from the Value property of each Slider in the sldColor control array to their respective color variables, lRed&, lGreen&, lBlue&. The color variables are then passed as parameters to the RGB() function. The return value of the RGB() function is used to set the BackColor property of the form.

Viewing Data with ListView and TreeView

The ListView and TreeView controls are two of the Windows Common Controls. These controls allow you to organize data for viewing in a manner similar to that used by the Windows Explorer (see Figure 10.13). You now will be guided through the creation of sample ListView and TreeView projects, but these are tricky controls to master. You might want to spend a little time going over the online help files that accompany your version of Visual Basic to get a good grounding in their use. It will be time well spent.

FIG. 10.13
The Windows 95 Explorer uses both the TreeView and ListView Win32 Common Controls.

The left pane uses the TreeView; the right pane uses the ListView.

Using the ListView Control

The ListView control is similar to the ListBox but is enhanced in a number of ways. It enables you to display a list with large icons, small icons, as a list, or as a report. These options correspond to the options in the Windows Explorer's View menu (Lar_ge Icons, Small Icons, List, or Details). In fact, the most common use of the ListView control is the right pane of the Explorer window (refer to Figure 10.13).

The ListView control can display information in one of a variety of modes--icon lists arranged from left to right, a columnar list, or a "report" view. Once the items are stored in the ListItems collection, it is simply a matter of setting the View property to switch to any of the desired modes.

The report-style list is special because it shows more information than the other modes. When using the Windows Explorer, you may have noticed that the Details option displays more information than just the file name. In this case, the file name is the main item, and the size, type, and date modified are "sub-items" associated with each file name.

In your programs, you control sub-items with the SubItems property, which is an array of strings associated with each item in the list. Also, a ColumnHeaders collection is used to supply the headings at the top of the report.

Recall from earlier in this chapter that your toolbar needs an associated ImageList control to supply the button pictures. The ListView control needs two ImageLists because it can display both large and small icons. These ImageLists can be set from the Property Pages dialog box or from code, as follows:

lViewMain.Icons = ImageList1
lViewMain.SmallIcons = ImageList2

If you don't set the SmallIcons and Icons properties of the ListView control, the associated list images will not appear. Also, it's a good idea to use the smaller ImageList dimension (16x16) when filling the image list that you are going to use for small icons.


NOTE: As with many of the other controls in the Common Controls group, ListView makes extensive use of collections. If you are unfamiliar with this concept, you may want to re-read the earlier section "Understanding Collections" for a quick introduction.

Recall that the ListBox control's items were stored in an array. All the items in a ListView control are in a collection called ListItems, which is necessary because each item in a list view has several properties, including an index to the icon images and a caption. As with the Toolbar's Buttons collection, the ListItems collection has an Add method defined as follows:

listview1.ListItems.Add ,"mykey","My Item",1,1

Starting the Project To illustrate the concepts of using the ListView control, a project will be created next that displays a list of baseball team standings in a ListView control.


NOTE: For your convenience, the complete project is available on the accompanying CD-ROM.

To begin the creation of the project, start a new project in Visual Basic and save it as LISTVIEW.VBP. Next, change the name of the default form to frmListV and save the form as FRMLISTV.FRM.

Next, add a ListView control to the form. For simplicity, make the ListView's name short, lvMain. Finally, you need to add two ImageList controls to the form. Again, make the names short, ilNormal and ilSmall.


NOTE: The ImageList and ListView controls must be added to your Toolbox before you can use them. See the earlier section "Working with the Windows Common Controls" for an explanation.

Setting the Properties of the ListView Control As with most controls, you can set up the ListView control in two ways--by using the Properties window and Property Pages or by using code. If you want to set up the ListView while you are in the design environment, you can use the Property Pages, shown in Figure 10.14. You will need to set three key properties: View, Icons, and SmallIcons.

FIG. 10.14
Property Pages let you set the ListView control properties.

First, you need to set the View property, which determines how the list will present information to the user. The View property has four possible values:

The names of the ImageList controls that contain the normal and small icons that are shown in the list are the other things that need to be set for the ListView control. If you are using the Property Pages, you can select the ImageList controls from drop-down lists on the Image List page. These lists contain the names of all the ImageList controls on your form.

As stated previously, you can also set the properties of the ListView control from your code. This is done in the sample project. The code in Listing 10.7 is placed in the Load event of the frmListV form.

Listing 10.7 FRMLISTV.FRM--Use the Load Event to Set Up the ListView Control

Private Sub Form_Load()
 
   `Set up the icons from the image List
    lvMain.Icons = ilNormal
    lvMain.SmallIcons = ilSmall
    
    ` Add ColumnHeaders.  The width of the columns is the width
    ` of the control divided by the number of ColumnHeader objects.
    Dim clmX As ColumnHeader   
    Set clmX = lvMain.ColumnHeaders.Add(, , "Team")
    Set clmX = lvMain.ColumnHeaders.Add(, , "Wins")
    Set clmX = lvMain.ColumnHeaders.Add(, , "Losses")
    
    `Create a ListItem object.
    Dim itmX As ListItem
    
    `Add some data setting to the ListItem
    `The Red Sox
    Set itmX = lvMain.ListItems.Add(, , "Red Sox", 1, 1)  `Team
    itmX.SubItems(1) = "64"   ` Wins
    itmX.SubItems(2) = "65"   ` Losses
     ` You can duplicate the above 3 lines of code
    ` to add information for more teams... 
    
    lvMain.View = lvwReport ` Set View property to Report.
End Sub

Figure 10.15 shows the results of the code.

FIG. 10.15
This is how the ListView control looks after being set up by your code.

Notice in Listing 10.7 that temporary object variables were used. For the code that set up the column headings, this was not really necessary. However, when the team was added, a key was not supplied. Therefore, the object itmX was needed to set the two sub-items. If a key had not been supplied, the code also could have been written as follows:

lvMain.ListItems.Add , "RSox", "Red Sox", 1, 1
lvMain.ListItems("RSox").SubItems(1) = "64"
lvMain.ListItems("RSox").SubItems(2) = "65"


Adding a ListItem Object to a ListView Control
In the examples in this section, the ListItems collection was introduced. The ListItems collection stores ListItem objects that are created using the Add method.

The syntax for a ListItem's Add method is as follows:

object.Add(index, key, text, icon, smallIcon)

Here's what the different pieces are and what they do:

If you want to add additional information, such as the file creation date or file size, to the created ListItem object, MyListItem, you manipulate the object's SubItems(Index) property. See your online Visual Basic documentation for additional information on the SubItems property.


Setting Up the ImageList Controls To provide the icons for the ListView control, you will need to have ImageList controls on your form as well. If you followed the earlier instructions for the baseball example, you already have two ImageList controls on the form. All that remains is to set the images in the list:

1. To begin, right-click the ImageList control, ilNormal. A context menu will appear.

2. Left-click the Properties menu item at the bottom of the context menu. The Property Pages dialog box for ilNormal will appear.

3. Select the Image tab and click the Insert Picture button.

4. Choose a bitmap or icon file (for example, a picture of a baseball). The bitmap is now inserted as the first image, as shown in Figure 10.16.

FIG. 10.16
Insert an icon or bitmap as the first image in ilNormal.

You then will need to repeat the process for ilSmall. Because this ImageList is for the SmallIcons property, first set the dimensions to 16 x 16 in the General tab.

Creating the Menu for the Project To make it easy for you to run different parts of the sample program, you will need to create a menu. Using the Menu Editor (Menu Editor button, or Tools, Menu Editor), create the menu items, as shown in Figure 10.17.

FIG. 10.17
The menu for FRMLISTV.FRM as shown in the Menu Editor.

After exiting the Menu Editor, you will need to add code to each menu item to make it perform a task. The code for each of these items is contained in Listing 10.8.

Listing 10.8 FRMLISTV.FRM--The Menu click Events for FRMLISTV.FRM

Private Sub mnuLarge_Click()
    lvMain.View = lvwIcon
End Sub
Private Sub mnuSmall_Click()
     lvMain.View = lvwSmallIcon
End Sub
Private Sub mnuList_Click()
     lvMain.View = lvwList
End Sub
Private Sub mnuDetail_Click()
     lvMain.View = lvwReport
End Sub
Private Sub mnuExit_Click()
    End
End Sub

See "Creating a Menu Bar," Chapter 5

Running the Program You now can run the program by clicking the Start button or by pressing F5. Figure 10.18 shows two different views of the same list.

FIG. 10.18
While the report view displays detailed information with column headings, the large icons view simply shows a picture above the item text.

In the Form_Load event, the ListItem objects (baseball teams) for the ListView's ListItem collection are created and added. As each ListItem is added to the ListItems collection, values are assigned to SubItems(1) (the "Win" column) and SubItems(2) (the "Loss" column) of the ListItem, itmX.

The menu has six menu items with the captions Large Icons, Small Icons, List, Details, a separator bar, and Exit. The Click event handlers of the first four menu items set the View property of the ListView control. The views are lvwIcons, lvwSmallIcons, lvwList, and lvwReport, respectively. The itmExit_Click event terminates the application.

You have just seen a sample project that demonstrates the ListView's ability to display items. Like the ListBox, however, the ListView control has many events and properties, such as the ItemClick event discussed below, designed to select and manipulate item(s).

The ItemClick event passes an object to your program, so you can take appropriate action:

Private Sub ListView1_ItemClick(ByVal Item As ComctlLib.ListItem)
    If Item.Text = "Magic Item" Then MsgBox "You clicked the magic item!"
End Sub

The ListView control has properties to sort the report view based on a column header. By using the ColumnClick event, it would be very easy to change the sort order to the selected column:

Private Sub lvMain_ColumnClick(ByVal ColumnHeader As ComctlLib.ColumnHeader)
lvMain.SortKey = ColumnHeader.Index - 1
lvMain.Sorted = True
End Sub

As you may have noticed, items in a ListView can be renamed by single-clicking the text. Two events, BeforeLabelEdit and AfterLabelEdit, lets your program know which item the user is changing.

As stated at the beginning of the chapter, the ListView and TreeView are fairly complex controls. To discover all the features, I suggest creating several sample programs to test all the properties and methods.

Using the TreeView Control

The TreeView control is similar to a ListView in that it can display items with a combination of text and graphics. However, the TreeView does so by showing items within a tree hierarchy. If you have taken a math or computer science class, you already may have discussed the "tree hierarchy." An example of a tree you might have seen in math class is shown in Figure 10.19.

FIG. 10.19
In this tree structure, each node of the tree is represented by a circle.

If you are unfamiliar with tree hierarchies, study the next few sections carefully, as this concept will make understanding the TreeView control a lot easier.


NOTE: If you have used the OutLine control in previous versions of Visual Basic, you'll find that the TreeView control is a more robust alternative.

Given the hierarchical nature of the TreeView control, root, parent, and child are fundamental concepts that must be understood for you to work effectively with the control. Also, the TreeView uses the Node object extensively. This being the case, mastery of the Node object is also a requirement for effective use of the TreeView. The most common example of the TreeView is the left pane of the Windows Explorer (refer to Figure 10.13).

Understanding Nodes A hierarchy is an organization in which each part has a defined relationship with the other parts. For example, take your family tree. Your parents and their parents are "above" you in the hierarchy; your children and their children are "below" you. In the family tree example, each person is considered to be a node on the tree. Relationships between nodes are indicated by branches. A node's branches can connect it to other nodes (for example, lines on the family tree connecting you to your parents), or it can simply exist by itself (if you don't have any children).

Like the family tree or a real-life tree, all TreeView controls have nodes. Nodes is (notice the use of the singular verb) both a property of a TreeView control and an object in itself. If you have followed the discussion up to now regarding collections, this concept probably makes some sense to you. (If you're unclear about collections, review the "Understanding Collections" section earlier in this chapter.) Like the Toolbar control's Buttons collection, the TreeView's Nodes collection has properties and methods, including an Add method used to create new nodes:

tv1.Nodes.Add , , "mykey", "Test Node", 1, 2

And, like the other Add methods discussed so far, it can return a reference to the object just created:

Dim tempNode As Node
Set tempNode = tv1.Nodes.Add(, , "mykey", "Test Node")
tempNode.Image = 1
tempNode.SelectedImage = 2
tempNode.ExpandedImage = 3

The TreeView control presents a "collapsible" view of the tree structure, as seen in Figure 10.20.

FIG. 10.20
A simple tree structure created in a TreeView control. In this figure, notice the use of plus, minus, lines, and images to indicate which parts of the tree are "expanded" and which are "collapsed."

Understanding the Root Property At the very top (or bottom, depending on how you look at it) of a tree structure is its root. A root is the node from which all other nodes descend. A tree has only one root node. In the tree pictured in Figure 10.20, the node called "Me" is the root node, simply because it was the first one added to the TreeView control. Part of what defines a node is its root. Therefore, each node in the Nodes collection has a Root property that refers to the tree's root node. For the tree pictured in Figure 10.20, the following code would verify that "Me" is the root of every node:

Dim tempNode As Node
For Each tempNode in tv1.Nodes
       Print tempNode.Text & "'s root is " & tempnode.Root.Text
Next tempNode

Note that Root is both a property of a node and a node itself.

Working with the Parent Property You have just seen that every node in the Nodes collection can access the root. However, just knowing the root of a node is not enough to define a position in the tree hierarchy. Look at, for example, Figure 10.21, which is a company organizational chart.

FIG. 10.21
Note in this particular TreeView control that the images for each node have been disabled.

If you want to know where you are in this structure, you need to know more than just where the root (President) is. This brings us to the first of several tree relationships, the Parent relationship. To be a parent, a node must have children. In Figure 10.21, the president of the company is a parent to both of the vice president nodes. Both managers shown in the figure also have the same parent, VP of Finance.

Suppose you were an ambitious little node trying to climb the corporate ladder. You could use this code to check your progress:

Dim MyNode As Node
Set MyNode = tv1.Nodes("Me")
If MyNode = MyNode.Root Then 
    MsgBox "You're the boss!"
Else
    MsgBox "Try getting promoted to " & MyNode.Parent.Text
End If

As you can see from the example, each node object has a Parent property that refers to its parent node. The only exception is the root node, whose Parent property does not refer to anything.

Working with the Children Property To be a parent, a node must have children. To find out if a node is a parent, you query the Children property by using code like this:

Private Sub TreeView1_NodeClick(ByVal MyNode As Node)
    If MyNode.Children = 0 Then
        MsgBox "I am not a parent"
    End If
End Sub

As you can see, the Children property returns an integer value that represents the number of children a given node has. To be considered a child, a node has to have a direct connection. In other words, as shown in Figure 10.21, the president of the company has two children--the two VPs.

Working with the Child Property Whereas the Children property simply returns the count of child nodes, the Child property returns an actual node (just like the Root and Parent properties). However, even if a parent has multiple children, the Child property returns only the first of the given parent node's descendants. If a given node doesn't have a child, its Child property will contain an invalid reference. Therefore, you should not try to access it if the Children property is 0. In Figure 10.21, Manager #2's Child property is Accountant #1. The immediate question that comes to mind is how to access child nodes other than the first one. Well, each node has several properties that are used to determine who its "brothers and sisters" are, as demonstrated in the following code:

Sub PrintAllChildren()
   
   Dim anyNode As Node
   Dim kidNode As Node
   Dim inCounter As Integer
   For Each anyNode In tv1.Nodes
     If anyNode.Children <> 0 Then `this node is a parent
     
        Print anyNode.Text & "`s children are: "
        Set kidNode = anyNode.child
        Print kidNode.Text
        
        inCounter = kidNode.FirstSibling.Index
        While inCounter <> kidNode.LastSibling.Index
           Print tv1.Nodes(inCounter).Next.Text
           inCounter = tv1.Nodes(inCounter).Next.Index
        Wend
   
     End If
   
  Next anyNode
End Sub

Remember, for a given node, there is only one child. All the other nodes that share the child's parent are considered Next or Previous nodes. However, among all the nodes that share the same value for the Parent property, there is a FirstSibling and a LastSibling.


NOTE: Nodes are tricky; there's no question about it. One of the best ways to get a grasp of nodes is to see the node code (no poetry intended) in action. The online help file examples that Microsoft provides with your version of VB are pretty good once you get a basic understanding of the hierarchy concepts. It is suggested that you create several test programs until you are comfortable using the TreeView control.

To learn more about the TreeView control, keep reading. This section focused on accessing nodes already in the TreeView control. The next section will add nodes to a TreeView control as part of a sample project.

Using the TabStrip Control

The last control that will be covered is the TabStrip control. The TabStrip, shown in Figure 10.22, adds a whole new dimension to form organization and information presentation. Of all the controls in the Common Controls group, it probably has attained the most prominence in the Windows interface arsenal.


NOTE: The TabStrip control is different from the tabbed dialog box. Aside from the visual difference, the most important distinction is that the TabStrip is not a container. Containers are discussed in Chapter 13, "Using Containers."

See "Using Tabbed Dialogs," Chapter 13

FIG. 10.22
A Property Pages dialog box is an example of using a TabStrip control.

Next, a sample project will be created to illustrate the capabilities of the TabStrip. In this sample project, the purpose of the TabStrip control will be to switch between two lists of information. The lists will be baseball teams displayed in a TreeView control. The TabStrip will enable you to select which league to display.

Starting the Project

To begin the TreeTab project, start a new project in Visual Basic. Next, rename the default form "Form1" to frmTreTb. Then follow these steps:

1. Add a TabStrip control and name it something short and meaningful, like tsMain.

2. Next, add a TreeView control to the form and name it tv1. Now you are ready to start setting the properties of the controls.


CAUTION: The TabStrip control is not a container. This means that controls placed in a TabStrip control do not assume the Visible, Enabled, and relative Top and Left properties of the TabStrip, as they would if you were to draw a control into a selected Frame control. Thus, clicking a TabStrip will bring it to the front, covering other controls that are before it.

To manipulate how controls appear in relation to a TabStrip, pay particular attention to the ZOrder method of the TabStrip and the affected controls. During design mode, you can right-click the TabStrip control and choose Send to Back.


Setting Up the TabStrip

The next step in creating the project is to create the tabs in the TabStrip. Because two leagues need to be shown, two tabs are needed in the TabStrip. To set up the TabStrip control, follow these steps:

1. Start by right-clicking tsMain. This will bring up the TabStrip context menu.

2. Click the Properties menu item at the bottom of the context menu to display the Property Pages dialog box for tsMain.

3. Click the Tabs tab and type American League in the Caption field (see Figure 10.23).

FIG. 10.23
The Property Pages dialog box makes it easy to insert tabs into a TabStrip control.

4. Click the Insert Tab button. A tab will be added.

5. In the Caption field, type National League.

6. Click OK. You will see that the captions have appeared in the TabStrip control.

Creating the Code to Set Up the TreeView Control

As was the case in the ListView project, the setup of the TreeView control is easier to accomplish through code. In the case of your sample project, you want to display a hierarchical organization of a selected baseball league. Each league has three divisions: East, West, and Central. The divisions have five, five, and four teams, respectively.

To take advantage of this common structure, put the data into two text files, ALEAGUE.TXT and NLEAGUE.TXT. These files will contain a list of the 14 teams in each league. They can be created in Notepad or any other text editor, as shown in Figure 10.24.

FIG. 10.24
In the sample program, the TreeView will be filed with items from the two text files pictured here.

Create the subroutine shown in Listing 10.9 to load information from the text files into the TreeView control.

Listing 10.9 FRMTRETB.FRM--DisplayLeague Procedure Displays League Information in the TreeView Control

Public Sub DisplayLeague(sLeague As String)
    Dim tempNode As Node
    Dim nCounter As Integer
    Dim sTemp As String
  
    tv1.Nodes.Clear
    
    `Add the League
    Set tempNode = tv1.Nodes.Add(, , "R", sLeague)
    
    `Add the Divisions
    Set tempNode = tv1.Nodes.Add("R", tvwChild, "E", "East Division")
    Set tempNode = tv1.Nodes.Add("R", tvwChild, "C", "Central Division")
    Set tempNode = tv1.Nodes.Add("R", tvwChild, "W", "West Division")
    
    `Open the text file with team names
    If sLeague = "National League" Then
    Open "C:\NLEAGUE.TXT" For Input As #1
    Else
    Open "C:\ALEAGUE.TXT" For Input As #1
    End If
    `Add the 5 EAST teams
    For nCounter = 1 To 5
        Line Input #1, sTemp
        Set tempNode = tv1.Nodes.Add("E", tvwChild, "E" & nCounter, sTemp)
   Next nCounter
    tempNode.EnsureVisible
    
    `Add the 5 CENTRAL teams
    For nCounter = 1 To 5
        Line Input #1, sTemp
        Set tempNode = tv1.Nodes.Add("C", tvwChild, "C" & nCounter, sTemp)
   Next nCounter
    tempNode.EnsureVisible
    `Add the 4 WEST teams 
    For nCounter = 1 To 4
        Line Input #1, sTemp
        Set tempNode = tv1.Nodes.Add("W", tvwChild, "W" & nCounter, sTemp)
   Next nCounter
    tempNode.EnsureVisible
    `Close the Input file
    Close #1
    `Set the Desired style
    tv1.Style = tvwTreelinesText
    tv1.BorderStyle = vbFixedSingle
    
    `Set the TreeView control on top
    tv1.ZOrder 0
End Sub

Notice that the relationships in the tree view are defined as a node is added. The Add method's first parameter lists a "relative" node and the second parameter lists the relationship to that relative. The constant tvwChild indicates the new node is a child of the relative node.

Taking Action in the Program

Now, return to the topic of the TabStrip control and set up the form's Load event. When the form first appears, you probably want it to show something, so call the DisplayLeague procedure to display the American League teams. The code for the Load event is shown in Listing 10.10.

Listing 10.10 FRMTRETB.FRM--Use the Load Event to Initialize the Program

Private Sub Form_Load()
    `Put the tree view on top of the tab
    tv1.ZOrder 0
    `Call our procedure
    DisplayLeague "American League"
End Sub

At this point, you can run your program and the American League teams will be displayed. However, clicking the TabStrip will have no effect on the TreeView because you have not yet added the necessary code to the TabStrip's Click event. This code, shown in Listing 10.11, calls the DisplayLeague procedure with the name of the desired league.

Listing 10.11 FRMTRETB.FRM--Switch Leagues by Clicking the Appropriate Tab

Private Sub tsMain_Click()
    Dim nTemp As Integer
  
   Temp = tsMain.SelectedItem.Index
    DisplayLeague tsMain.Tabs(nTemp).Caption
End Sub

Now your sample program is done. Figure 10.25 shows how the program looks. FIG. 10.25 The sample application displays a list of base-ball teams when a tab is clicked.

Understanding How the Application Works

The crux of the project is the DisplayLeague procedure. First, this procedure creates a node for the League divisions:

Set tempNode = tv1.Nodes.Add("R", tvwChild, "E", "East Division")

The constant tvwChild tells the application to make this new node a child of the node, "R".

Then, to each Division node, several team nodes are added:

Set tempNode = tv1.Nodes.Add("E", tvwChild, "E" & nCounter, sTemp)

Notice that the first argument in the Add method is now "E", which is the unique key of the Node of the Eastern Division. This is how the "E1" node (which displays Yankees) knows that it is a child of the Eastern Division.

Next, the entire Division node and its children are told to remain expanded (TreeView nodes can be expanded and collapsed) in the line:

MyNode.EnsureVisible

(You also could have set each Division node's Expanded property to True.)

The last thing that deserves attention is the way the TabStrip reports back which tab has been clicked. In the TabStrip control, tabs are an array of, well, tabs. So, when you click a tab, you are actually selecting a tab, like selecting a ListIndex in a ListBox control. In light of this, to find out which tab is being clicked, the following line makes a bit more sense:

nTemp = tsMain.SelectedItem.Index

From Here...

The Windows Common Controls covered in this chapter can enhance your programs in many ways. Each has its own special capabilities that can improve the interface of your applications. The best way to learn about them is to put them in your programs and try them out. Some of the topics mentioned here are covered in more detail in other chapters:


Previous chapterNext chapterContents


Macmillan Computer Publishing USA

© Copyright, Macmillan Computer Publishing. All rights reserved.