Scroll Bars

 

With many VB controls, such as the listbox, multi-line textbox, treeview, listview and so on, vertical and/or horizontal scroll bars automatically appear on these controls and function as needed with little or no extra programming required. However, there may be times when you need to apply your own scroll bar functionality to an application. For such occasions, the Veritcal Scroll Bar (VScrollBar) and Horizontal Scroll Bar (HScrollBar) controls are available in the VB toolbox.

 

A scroll bar control consists of a bar with arrows at each end. Between the arrows is a square scroll box (also called a "thumb"). The scroll box slides along the scroll shaft between the two arrows.

 

Scroll bars are most frequently used to let the user move the contents of an area to bring into view a portion temporarily outside the visible region. A scroll bar control can also be used to specify a value within a prescribed range. By moving the scroll box between the two arrows, the user can specify a value in an intuitive, visual manner.

 

The scroll box on the scroll shaft indicates the current value specified by the bar. When the user clicks the arrow at either end of the scroll bar, the scroll box moves and incremental unit toward that arrow. When the user clicks the scroll shaft somewhere between an arrow and the scroll box, it moves a larger incremental unit toward the click position. In addition, the user can directly drag the scroll box along the shaft with the mouse.

 

When using a scroll bar control, you must determine the range of values that the control can designate. A scroll bar control can represent integer values in the range -32768 through +32767. You use the Minimum property to specify the low end of your range and the Maximum property to specify the high end of your range. The Value property specifies the current value represented by the scroll bar. The position of the scroll box along the scroll shaft graphically reflects where Value lies between Minimum and Maximum. If the user moves the scroll box, the Value property adjusts appropriately. If you modify the Vaue in program code, VB moves the scroll box to the appropriate position. The SmallChange property indicates how much the Value changes when the user clicks one of the arrows at the end of the scroll bar. The LargeChange indicates how much Value changes when the user clicks the scroll shaft between the scroll box and one of the arrows.

 

A Very Simple Example

 

In the very simple example that follows, a label is used to display the value of the scroll bar as it changes by the user clicking the arrows or moving the scroll box. To build the example, start a new project, place a label control and a vertical scroll bar (VScrollBar) control on the form and set their properties as indicated in the callouts below:

 

This sample program requires only a single line of code in the vertical scroll bar's ValueChanged event:

 

    Private Sub vsbTest_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles vsbTest.ValueChanged

 

        lblTest.Text = CStr(vsbTest.Value)

 

    End Sub

 

When you run the program, you will see that the value displayed in the label will vary as you click on the scroll bar's arrows or move its scroll box.

 

Note: When a scroll bar has focus, its scroll box will blink. Some people find this annoying. In most cases, you can prevent this blinking by setting the TabStop property of the scroll bar to False (the default is True). An exception to this is when the scroll bar is the only control on the form that can receive focus – such is the case in this example.

 

Download the VB project code for the example above here.

 

A More Advanced Example

 

In this example, a "manual" data grid has been created. With the various advanced controls that can be used with VB, such as the DataGridView, ListView, third-party girds, etc., you would most likely not have the need to build something like this – but you never know. This is a "low-tech" grid built with basic toolbox controls: a handful of labels, some images, a vertical scroll bar, and a horizontal scroll bar.

 

The application displays data about the twelve zodiac signs (Aires, Taurus, Gemini, Cancer, Leo, Virgo, Libra, Scorpio, Sagittarius, Capricorn, Aquarius, and Pisces). Note that there are only seven "rows" on the form, so vertical scrolling is necessary to view the twelve zodiac "records".

 

Associated with each sign are 15 fields: sign description, house, gemstone, New Age stone, colors, opposite sign, least compatible signs, ruling planet, element, anatomy, flower, most compatible signs, Tarot card, positive characteristics, and negative characteristics. Note that there are only four "columns" on the form, so horizontal scrolling is necessary to view the 15 fields.

 

When the program first runs, the form looks like this:

 

 

 

Screen shot after scrolling down (vertically):

 

 

 

Screen shot after scrolling across (horizontally):

 

 

 

Building the Zodiac Example

 

The design-time form is shown on the right. To show the images for the signs, on the far left-hand side of the screen we have a set of seven PictureBoxes named picSign0 thru picSign6. Moving to the right, we have four columns of seven labels each for the data, named lblCell1_0 thru lblCell1_6, lblCell2_0 thru lblCell2_6, lblCell13_0 thru lblCell3_6, and lblCell14_0 thru lblCell4_6, respectively. The column headings going across are named lblColHdrSign (this one has the text "Sign" and does not vary, because we keep the "Sign" column frozen), followed by lblColHdr1 thru lblColHdr3. The technique to simulate control arrays is used for all sets of controls just described.

 

On the far right-hand side of the screen, we have a vertical scroll bar named vsbZGrid to scroll the "records" down; and on the bottom below the columns of labels we have a horizontal scroll bar named hsvbZGrid to scroll the "fields" across.

The images for the signs are stored in an ImageList control named imlSigns.

The images are set of icons that were loaded ImageList control via its "Images Collection Editor" dialog.

 

 

A discussion of the code follows.

 

General Declarations Section

 

The General Declarations section declares a Structure named ZodiacRecord, based on the data in the input file. An array variable, maudtZodiacRec, is then defined as that structure type. It is expected that exactly 12 records will be read from the input file, so the array is declared with a fixed number (12) of elements (specified as 0 to 11). Two form-level variables (mintRowStart and mintColStart) are also declared. These variables specify the row and column starting points for transferring data from the structure array to the controls on the form.

 

    Private Structure ZodiacRecord

        Dim SignDesc As String

        Dim House As String

        Dim Gemstone As String

        Dim NewAgeStone As String

        Dim Colors As String

        Dim OppositeSign As String

        Dim LeastCompat As String

        Dim RulingPlanet As String

        Dim Element As String

        Dim Anatomy As String

        Dim Flower As String

        Dim MostCompat As String

        Dim TarotCard As String

        Dim PositiveChars As String

        Dim NegativeChars As String

    End Structure

 

    Private maudtZodiacRec(0 To 11) As ZodiacRecord

 

    Private mintRowStart As Integer

    Private mintColStart As Integer

 

Form Load Event

 

The Load event for the form opens the "NewZodiac.txt" input file and loads it into the structure record array. The mintRowStart and mintColStart variables are initialized to 1 and 2 respectively. The SetColumnHeaders and DisplayZodiacData Subs are then called to provide the initial display of the data.

 

    Private Sub SetColumnHeaders()

 

        Select Case mintColStart

            Case 2

                lblColHdr1.Text = "House"

                lblColHdr2.Text = "Gemstone"

                lblColHdr3.Text = "New Age Stone"

            Case 3

                lblColHdr1.Text = "Gemstone"

                lblColHdr2.Text = "New Age Stone"

                lblColHdr3.Text = "Colors"

            Case 4

                lblColHdr1.Text = "New Age Stone"

                lblColHdr2.Text = "Colors"

                lblColHdr3.Text = "Opposite Sign"

            Case 5

                lblColHdr1.Text = "Colors"

                lblColHdr2.Text = "Opposite Sign"

                lblColHdr3.Text = "Least Compatible Signs"

            Case 6

                lblColHdr1.Text = "Opposite Sign"

                lblColHdr2.Text = "Least Compatible Signs"

                lblColHdr3.Text = "Ruling Planet"

            Case 7

                lblColHdr1.Text = "Least Compatible Signs"

                lblColHdr2.Text = "Ruling Planet"

                lblColHdr3.Text = "Element"

            Case 8

                lblColHdr1.Text = "Ruling Planet"

                lblColHdr2.Text = "Element"

                lblColHdr3.Text = "Anatomy"

            Case 9

                lblColHdr1.Text = "Element"

                lblColHdr2.Text = "Anatomy"

                lblColHdr3.Text = "Flower"

            Case 10

                lblColHdr1.Text = "Anatomy"

                lblColHdr2.Text = "Flower"

                lblColHdr3.Text = "Most Compatible Signs"

            Case 11

                lblColHdr1.Text = "Flower"

                lblColHdr2.Text = "Most Compatible Signs"

                lblColHdr3.Text = "Tarot Card"

            Case 12

                lblColHdr1.Text = "Most Compatible Signs"

                lblColHdr2.Text = "Tarot Card"

                lblColHdr3.Text = "Positive Characteristics"

            Case 13

                lblColHdr1.Text = "Tarot Card"

                lblColHdr2.Text = "Positive Characteristics"

                lblColHdr3.Text = "Negative Characteristics"

        End Select

 

    End Sub

 

SetColumnHeaders Sub

 

This Sub sets the column headings based on the current value of mintColStart (which will be a number from 2 to 13, the min/max range of the horizontal scroll bar). A set of headings from "House" thru "New Age Stone" (fields 2 thru 4) to "Tarot Card" thru "Negative Characteristics" (fields 13 thru 15) will be assigned to elements 1 thru 3 of the lblColHdr control array. Note that only elements 1, 2, and 3 of the lblColHdr control array are changed. Element 0 is reserved for "Sign", which remains frozen as the other columns scroll to the right or left.

 

    Private Sub SetColumnHeaders()

 

        Select Case mintColStart

            Case 2

                lblColHdr1.Text = "House"

                lblColHdr2.Text = "Gemstone"

                lblColHdr3.Text = "New Age Stone"

            Case 3

                lblColHdr1.Text = "Gemstone"

                lblColHdr2.Text = "New Age Stone"

                lblColHdr3.Text = "Colors"

            Case 4

                lblColHdr1.Text = "New Age Stone"

                lblColHdr2.Text = "Colors"

                lblColHdr3.Text = "Opposite Sign"

            Case 5

                lblColHdr1.Text = "Colors"

                lblColHdr2.Text = "Opposite Sign"

                lblColHdr3.Text = "Least Compatible Signs"

            Case 6

                lblColHdr1.Text = "Opposite Sign"

                lblColHdr2.Text = "Least Compatible Signs"

                lblColHdr3.Text = "Ruling Planet"

            Case 7

                lblColHdr1.Text = "Least Compatible Signs"

                lblColHdr2.Text = "Ruling Planet"

                lblColHdr3.Text = "Element"

            Case 8

                lblColHdr1.Text = "Ruling Planet"

                lblColHdr2.Text = "Element"

                lblColHdr3.Text = "Anatomy"

            Case 9

                lblColHdr1.Text = "Element"

                lblColHdr2.Text = "Anatomy"

                lblColHdr3.Text = "Flower"

            Case 10

                lblColHdr1.Text = "Anatomy"

                lblColHdr2.Text = "Flower"

                lblColHdr3.Text = "Most Compatible Signs"

            Case 11

                lblColHdr1.Text = "Flower"

                lblColHdr2.Text = "Most Compatible Signs"

                lblColHdr3.Text = "Tarot Card"

            Case 12

                lblColHdr1.Text = "Most Compatible Signs"

                lblColHdr2.Text = "Tarot Card"

                lblColHdr3.Text = "Positive Characteristics"

            Case 13

                lblColHdr1.Text = "Tarot Card"

                lblColHdr2.Text = "Positive Characteristics"

                lblColHdr3.Text = "Negative Characteristics"

        End Select

 

    End Sub

 

DisplayZodiacData Sub

 

This Sub populates the lblCell1, lblCell2, lblCell3, and lblCell4 control arrays based on the current values of mintRowStart and mintColStart. The mintRowStart variable will contain a value between 1 and 6, the min/max range of the vertical scroll bar. This means that data for records 1 thru 7, 2 thru 8, 3 thru 9, 4 thru 10, 5 thru 11, or 6 thru 12 will be loaded into elements 0 thru 6 of the lblCellx arrays. Similarly, the value of mintColStart will be a number from 2 to 13, the min/max range of the horizontal scroll bar. This means that the set of fields from "House" thru "NewAgeStone" (fields 2 thru 4) to "TarotCard" thru "NegativeChars" (fields 13 thru 15) will be loaded into the appropriate element of lblCell2, lblCell3, and lblCell4.

 

    Private Sub DisplayZodiacData()

 

        Dim intX As Integer

        Dim intRecordIndex As Integer

        Dim picSign As PictureBox

        Dim lblCell1 As Label

        Dim lblCell2 As Label

        Dim lblCell3 As Label

        Dim lblCell4 As Label

 

        intRecordIndex = mintRowStart - 1

 

        For intX = 0 To 6

            picSign = DirectCast(GetControlByName(Me, "picSign" & intX), PictureBox)

            lblCell1 = DirectCast(GetControlByName(Me, "lblCell1_" & intX), Label)

            lblCell2 = DirectCast(GetControlByName(Me, "lblCell2_" & intX), Label)

            lblCell3 = DirectCast(GetControlByName(Me, "lblCell3_" & intX), Label)

            lblCell4 = DirectCast(GetControlByName(Me, "lblCell4_" & intX), Label)

            With maudtZodiacRec(intRecordIndex)

                lblCell1.Text = .SignDesc

                picSign.Image = imlSigns.Images(intRecordIndex)

                Select Case mintColStart

                    Case 2

                        lblCell2.Text = .House

                        lblCell3.Text = .Gemstone

                        lblCell4.Text = .NewAgeStone

                    Case 3

                        lblCell2.Text = .Gemstone

                        lblCell3.Text = .NewAgeStone

                        lblCell4.Text = .Colors

                    Case 4

                        lblCell2.Text = .NewAgeStone

                        lblCell3.Text = .Colors

                        lblCell4.Text = .OppositeSign

                    Case 5

                        lblCell2.Text = .Colors

                        lblCell3.Text = .OppositeSign

                        lblCell4.Text = .LeastCompat

                    Case 6

                        lblCell2.Text = .OppositeSign

                        lblCell3.Text = .LeastCompat

                        lblCell4.Text = .RulingPlanet

                    Case 7

                        lblCell2.Text = .LeastCompat

                        lblCell3.Text = .RulingPlanet

                        lblCell4.Text = .Element

                    Case 8

                        lblCell2.Text = .RulingPlanet

                        lblCell3.Text = .Element

                        lblCell4.Text = .Anatomy

                    Case 9

                        lblCell2.Text = .Element

                        lblCell3.Text = .Anatomy

                        lblCell4.Text = .Flower

                    Case 10

                        lblCell2.Text = .Anatomy

                        lblCell3.Text = .Flower

                        lblCell4.Text = .MostCompat

                    Case 11

                        lblCell2.Text = .Flower

                        lblCell3.Text = .MostCompat

                        lblCell4.Text = .TarotCard

                    Case 12

                        lblCell2.Text = .MostCompat

                        lblCell3.Text = .TarotCard

                        lblCell4.Text = .PositiveChars

                    Case 13

                        lblCell2.Text = .TarotCard

                        lblCell3.Text = .PositiveChars

                        lblCell4.Text = .NegativeChars

                End Select

            End With

            intRecordIndex = intRecordIndex + 1

        Next

 

    End Sub

 

GetControlByName Function

 

Helper function to implement "control array" functionality.

 

    Private Function GetControlByName(ByVal pobjParent As Control, _

                                      ByVal pstrCtlName As String) _

    As Control

 

        Dim objCtl As Control

 

        For Each objCtl In pobjParent.Controls

            If objCtl.Name = pstrCtlName Then

                Return (objCtl)

            End If

        Next

 

        ' if control is not found

        Return Nothing

 

    End Function

 

hsbZGrid_ValueChanged Event

 

This event will occur when the user changes the value of the horizontal scroll bar by clicking on its arrows or dragging its scroll box. The value will be set to a number between 2 and 13, and this is assigned to mintColStart. The SetColumnHeaders and DisplayZodiacData Subs are then called to update the display based on the new value of the horizontal scroll bar.

 

    Private Sub hsbZGrid_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles hsbZGrid.ValueChanged

 

 

        mintColStart = hsbZGrid.Value

 

        SetColumnHeaders()

 

        DisplayZodiacData()

 

    End Sub

 

vsbZGrid_ValueChanged Event

 

This event will occur when the user changes the value of the vertical scroll bar by clicking on its arrows or dragging its scroll box. The value will be set to a number between 1 and 6, and this is assigned to mintRowStart. The DisplayZodiacData Sub is then called to update the display based on the new value of the vertical scroll bar.

 

    Private Sub vsbZGrid_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles vsbZGrid.ValueChanged

 

        mintRowStart = vsbZGrid.Value

 

        DisplayZodiacData()

 

    End Sub

 

btnExit_Click Event

 

Ends the program.

 

    Private Sub btnExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExit.Click

        Me.Close()

    End Sub

 

 

Download the VB project code for the example above here.