Table Lens Example

These instructions will build an example program that looks like this:

A table lens provides a detail-in-context view of a table of statistics.  Clicking on a row toggles between a collapsed and expanded view of the row.  Clicking the collapse all button will collapse all rows and clicking the expand all button will expand all rows.  Clicking on each column heading (Name, Salary, Age) will sort the table by that column.

Each row of the table contains 3 labels, one for each of name, salary, and age.  When the row is collapsed, we remove the text from the label and change its size and background color to red.  When the row is expanded, we place the text back into each label and change its size and background color back to normal.  We use an array of a Person class to store the details (e.g., name, salary, age) for each row of the table.  This way we don't lose a row's details when we collapse it.

Download the code by clicking on the Zip file.

Instructions for Creating the Example:

  1. Start Visual Studio from the Start menu.
  2. Click on the New Project button in the bottom of the screen.
  3. Select Visual Basic Projects, and Windows Application.  In the Name box give your project a name.
  4. Layout your form like this:

5.  Create a new class named Person.  Right click on your Project in the Solution Explorer and choose Add and then Add Class from the context menu.  Choose the name Person.vb for your class file.

6. Our class will contain fields for a record, much like a database table.  In your class, type this code:

Public Class Person
    Public Name As String
    Public Salary As Long
    Public Age As Integer
    Public Expanded As Boolean
End Class

 

7. At the top of your code window, add an import statement, and declarations for a set of arrays.

Imports System.IO

Public Class Form1
Inherits System.Windows.Forms.Form

    ' create an array to store info about each person
    Dim People(20) As Person
    ' an array of labels for names
    Dim lblName() As Label
    ' an array of labels for salaries
    Dim lblSalary() As Label
    ' an array of labels for ages
    Dim lblAge() As Label

...

8. Create a Form Load sub routine by double clicking on the form.  Add some code to load up the table by allocating arrays of labels:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim i As Integer
    Dim count As Integer
    count = 20

    ' resize the arrays of labels for the number of rows we will have in our table

    ReDim lblName(20)
    ReDim lblSalary(20)
    ReDim lblAge(20)

    If File.Exists("data.txt") Then

        ' grab the records from a file
        Dim sr As New StreamReader("data.txt")

        For i = 0 To count - 1
            People(i) = New Person()
            People(i).Name = sr.ReadLine
            People(i).Salary = sr.ReadLine
            People(i).Age = sr.ReadLine
            People(i).Expanded = True

            ' setup the name label for this row
            lblName(i) = New System.Windows.Forms.Label()
            With lblName(i)
                .Text = People(i).Name
                .Size = New Size(96, 16) ' I experimented to get the row size I want
                .Location = New Point(4, 85 + i * 18) ' place each row below the previous row
                ' change the mouse cursor when someone hovers over this label
                .Cursor = Cursors.Hand
                .Tag = i
                ' wire this label to the click event handler for every cell in the table
                AddHandler .Click, AddressOf Me.TableClick
            End With

            ' setup the salary label for this row
            lblSalary(i) = New System.Windows.Forms.Label()
            With lblSalary(i)
                .Text = People(i).Salary
                .Size = New Size(96, 16) ' I experimented to get the row size I want
                .Location = New Point(105, 85 + i * 18) ' place each row below the previous row
                ' change the mouse cursor when someone hovers over this label
                .Cursor = Cursors.Hand
                .Tag = i
                ' wire this label to the click event handler for every cell in the table
                AddHandler .Click, AddressOf Me.TableClick
            End With

            ' setup the age label for this row

            lblAge(i) = New System.Windows.Forms.Label()
            With lblAge(i)
                .Text = People(i).Age
                .Size = New Size(96, 16) ' I experimented to get the row size I want
                .Location = New Point(210, 85 + i * 18) ' place each row below the previous row
                ' change the mouse cursor when someone hovers over this label
                .Cursor = Cursors.Hand
                .Tag = i
                ' wire this label to the click event handler for every cell in the table
                AddHandler .Click, AddressOf Me.TableClick
            End With

            ' add the label arrays to the form so they are visible

            Me.Controls.AddRange(lblName)
            Me.Controls.AddRange(lblSalary)
            Me.Controls.AddRange(lblAge)
        Next
        sr.Close()
    End If

End Sub

9. Add the TableClick event that we wired up each label to.  It will simply expand or collapse a row when one of the labels in our table is clicked.

Private Sub TableClick(ByVal sender As System.Object, ByVal e As System.EventArgs)
    ' collapse the row if it is expanded
    If People(sender.Tag).Expanded = True Then
        CollapseRow(sender.Tag)
    ' otherwise expand the row
    Else
        ExpandRow(sender.Tag)
    End If
End Sub

10. Add two subroutines, one for expanding a row, and one for collapsing a row.

Private Sub ExpandRow(ByVal Row As Integer)
' this expands one row

    People(Row).Expanded = True
    ' fill in the actual values for the labels
    lblName(Row).Text = People(Row).Name
    lblSalary(Row).Text = People(Row).Salary
    lblAge(Row).Text = People(Row).Age

    ' resize the labels
    lblName(Row).Size = New Size(96, 16)
    lblSalary(Row).Size = New Size(96, 16)
    lblAge(Row).Size = New Size(96, 16)

    ' change the color of the labels to the standard control color
    lblSalary(Row).BackColor = SystemColors.Control
    lblAge(Row).BackColor = SystemColors.Control

    ' reposition the labels based on the row right above it

    If Row <> 0 Then
        lblName(Row).Location = New Point(4, lblName(Row - 1).Top + lblName(Row - 1).Height + 2)
        lblSalary(Row).Location = New Point(105, lblSalary(Row - 1).Top + lblSalary(Row - 1).Height + 2)
        lblAge(Row).Location = New Point(210, lblAge(Row - 1).Top + lblAge(Row - 1).Height + 2)
    End If

End Sub
 

Private Sub CollapseRow(ByVal Row As Integer)
' this collapses one row

    People(Row).Expanded = False
    ' fill in the actual values for the labels
    lblName(Row).Text = ""
    lblSalary(Row).Text = ""
    lblAge(Row).Text = ""

    ' resize the labels

    lblName(Row).Size = New Size(96, 8)
    lblSalary(Row).Size = New Size(People(Row).Salary / 10000, 8)
    lblAge(Row).Size = New Size(People(Row).Age, 8)

    ' change the color of the labels to red

    lblSalary(Row).BackColor = Color.Red
    lblAge(Row).BackColor = Color.Red

    ' reposition the labels based on the row right above it
    ' put them really close together

    If Row <> 0 Then
        lblName(Row).Location = New Point(4, lblName(Row - 1).Top + lblName(Row - 1).Height + 1)
        lblSalary(Row).Location = New Point(105, lblSalary(Row - 1).Top + lblSalary(Row - 1).Height + 1)
        lblAge(Row).Location = New Point(210, lblAge(Row - 1).Top + lblAge(Row - 1).Height + 1)
    End If
End Sub

11. Double click on the Collapse All button on your form and add this code to its Click subroutine.  It will just collapse each row one at a time.

Private Sub btnCollapseAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCollapseAll.Click
    Dim i As Integer
    For i = 0 To 19
        CollapseRow(i)
    Next
End Sub

12. Double click on the Expand All button on your form and add this code to its Click subroutine.  It will just expand each row one at a time.

Private Sub btnExpandAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExpandAll.Click
    Dim i As Integer
    For i = 0 To 19
        ExpandRow(i)
    Next
End Sub

13. When someone clicks the column headings (Name, Salary, Age), we will sort using an insertion sort.  Add this subroutine containing an insertion sort.

Private Sub InsertionSort(ByVal Mode As Integer)
' mode 1 = sort by Name
' mode 2 = sort by Salary
' mode 3 = sort by Age


    Dim i As Integer
    Dim Low As Integer
    Dim High As Integer
    Dim Val1 As Object
    Dim Val2 As Object
    Dim Temp As Person

    ' be sure to start at the second position in the array

    For i = 1 To 19
        High = i
        Do
            Low = High - 1

            Select Case Mode
            Case 1
                Val1 = People(Low).Name
                Val2 = People(High).Name
            Case 2
                Val1 = People(Low).Salary
                Val2 = People(High).Salary
            Case 3
                Val1 = People(Low).Age
                Val2 = People(High).Age
            End Select


            If (Val1 > Val2) Then

                ' swap

                Temp = People(Low)
                People(Low) = People(High)
                People(High) = Temp

                High = Low
            Else
                Exit Do
            End If
        Loop Until High <= 0
    Next
End Sub

14. Add the following subroutines to the Click event for each of your buttons, Name, Salary, Age to sort the table.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    ' the Name button
    InsertionSort(1)

    ' rebuild the table in the new sorted order

    Dim i As Integer
    For i = 0 To 19
        If People(i).Expanded Then
            ExpandRow(i)
        Else
            CollapseRow(i)
        End If
    Next
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    ' the Salary button
    InsertionSort(2)

    ' rebuild the table in the new sorted order
    Dim i As Integer
    For i = 0 To 19
        If People(i).Expanded Then
            ExpandRow(i)
        Else
            CollapseRow(i)
        End If
    Next
End Sub

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    ' the Age button
    InsertionSort(3)

    ' rebuild the table in the new sorted order
    Dim i As Integer
    For i = 0 To 19
        If People(i).Expanded Then
            ExpandRow(i)
        Else
            CollapseRow(i)
        End If
    Next
End Class