Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / Visual Basic
Article

VS.NET like toolbox control

Rate me:
Please Sign up or sign in to vote.
4.73/5 (13 votes)
12 Feb 20044 min read 125.2K   866   37   8
Collapsing and expanding panel toolbar

Sample Image - screenshot.png

Simple ToolBar control

As I was working on my editor I decided I needed a toolbox control like the one in VS.NET. Instead of going out and trying to find a control on the net that wouldn't do what I wanted anyway, I thought it would be fun just to roll my own.

Overview

This control inherits from the panel object. Basically what it does is draw, position, collapse and expand the panels on screen to get the effect you want out of the control. You can also add any other control (textbox in the case of the demo) you want to the panel object.

Each ToolBar contains multiple ToolPanel's.

Methods and Properties

ToolBar.new([dockStyle], [width]) Overloaded ConstructorCreates the ToolBar object
ToolBar.count[ReadOnly]PropertyReturns the number of panels
ToolBar.item(integer)PropertyReturns a panel object
ToolBar.Remove(string)MethodRemoves a panel
ToolBar.View(Object)MethodBrings a panel into view
ToolBar.Add(String)MethodAdds a panel
ToolPanel.new(String)ConstructorCreates a ToolPanel object
ToolPanel.Title[ReadOnly]PropertyReturns the Title
ToolPanel.State[ReadOnly]Property/Enum Returns the object state
ToolPanel.captionArea[ReadOnly]PropertyReturns a rectangle of the caption dimensions
ToolPanel.clientArea[ReadOnly]PropertyReturns a rectangle of the client dimensions
ToolPanel.captionHeight(integer)PropertyReturns/Sets the size of the caption
ToolPanel.MaximizeMethodAlthough public do not call this, resets the docks
ToolPanel.Minimize(Object)MethodAlthough public do not call this, resets the docks

Simple Example

The first thing you need to do is import the namespace. This can be done at the top of your code by typing Imports Toolbar. The next thing you will need to do is declare an instance of the object and add it to your form. There are a bunch of ways to do this, you can declare it as a Friend and add it as a control in initialize components or you can simply declare it as public in the main body of your code. What solution is right for you depends on if it needs to dock in a certain order on your form. For instance if you have a statusbar on your form you will want to declare it as a friend and add it to the initialization. Here are both examples:

Initialization method:

VB.NET
Private components As System.ComponentModel.IContainer
...
...
...
Friend Toolbar As New Toolbar.Initalize(DockStyle.Left, 175)
Friend WithEvents Textbox2 As System.Windows.Forms.TextBox
Friend WithEvents Button2 As System.Windows.Forms.Button
Friend WithEvents Label2 As System.Windows.Forms.Label
<System.Diagnostics.DebuggerStepThrough()>
    Private Sub InitializeComponent()
  ...
  ...
  ...
Me.Controls.Add(Me.Toolbar)
Me.Controls.Add(Me.Textbox2)
Me.Controls.Add(Me.Button2)
  ...
  ...
  ...

Public Method:

VB.NET
Public Toolbar as new toolbar()

Now that you have created the object you can use it by calling toolbar.add("My Tab") like this..

VB.NET
Private Sub Button1_Click(ByVal sender As System.Object, _
               ByVal e As System.EventArgs) Handles Button1.Click
    Toolbar.add(TextBox.Text)
End Sub

While this is functional its not very interesting, to spice things up a bit we need to add another control to the panel (no since having an empty panel). For this I have created another class called panelContents. You do not need to do it this way, you could just use Controls.Add(new textbox). Lets take a look at the code:

VB.NET
' This class just creates a textbox object already
' loaded with a few options
'
Public Class panelContents : Inherits TextBox
    Sub New(ByVal txt As String)
        Me.Multiline = True
        Me.Dock = DockStyle.Fill
        Me.BorderStyle = BorderStyle.None
        Me.ScrollBars = ScrollBars.Vertical
        Me.Text = txt
    End Sub
End Class


Private Sub Button1_Click(ByVal sender As System.Object, _
             ByVal e As System.EventArgs) Handles Button1.Click

    ' Create a new Panel
    Dim thisPanel As ToolPanel = Toolbar.add(TextBox.Text)


    ' Put a textbox in the panel
    thisPanel.Controls.Add(New panelContents("This is " & TextBox.Text))

End Sub

One more thing of noted importance is the Remove method. You can call this in you program like so

VB.NET
Private Sub Button2_Click(ByVal sender As System.Object, _
              ByVal e As System.EventArgs) Handles Button2.Click
    Toolbar.Remove(Textbox2.Text)
End Sub

ToolBar Class

I am going to skip the overloaded new constructors and the properties for the class and focus on the important things, namely add, remove and view. There is one important thing you need to know before we gets started, all the ToolBerPanel objects are stored in an internal array called Panels.

Add function:

VB.NET
'------------------------------------------------------
'          Sub: add
'  Description: Create a new panel
'
Public Function add(ByVal name As String) As ToolPanel
    MinimizeAll()               ' Make sure they are all minimized

    Dim newPanel = New ToolPanel(name, Me)
      ' Create the panel w/ a ref back to here
    Panels.Add(newPanel)         ' Add to master array

    Dim orderPanels As New ArrayList ' Array of panels
    Dim thisPanel As ToolPanel


    For Each thisPanel In Panels.ToArray
                ' Copy the panels to the array
        orderPanels.Add(thisPanel)
    Next


    orderPanels.Reverse()

    Me.Controls.Clear()
        ' Clear out the controls
    Me.Controls.Add(newPanel)
       ' Add the most recent control

    For Each thisPanel In orderPanels.ToArray ' Add the Bottom
        Me.Controls.Add(thisPanel)
          ' Addrange isn't working, humm.
    Next

    Console.WriteLine("Panels: " & orderPanels.Count + 1)
    Return newPanel
End Function

What the add function does is:

  • Collapse all the panels
  • Create a new panel
  • Add it to the internal array
  • Insert the control and append the reverse list of existing controls into the Controls of the component.
  • Returns the new object

Remove Function:

VB.NET
'------------------------------------------------------
'          Sub: Remove
'  Description: Search for the panel and if found
'               remove it and expand the one before it
'
Public Sub Remove(ByVal Title As String)
    Dim tmp As ToolPanel
    Dim index As Integer

    For Each tmp In Panels.ToArray
        If tmp.Title.ToLower = Title.ToLower Then
            index = Panels.IndexOf(tmp)
            Panels.Remove(tmp)
            Me.Controls.Remove(tmp)
            tmp.Dispose()


            If index >= 1 Then
                Panels(index - 1).maximize()
            End If
        End If
    Next
End Sub

What the remove function does is:

  • Looks at all the panels to find a match
  • Removes the panel from the array
  • Removes the panel from the control
  • Frees up the memory used by the panel
  • Maximizes the panel above it (so not to have empty space)

The View function

VB.NET
'------------------------------------------------------
'          Sub: View
'  Description: Bring this panel in to view
'
Public Sub View(ByVal panel As ToolPanel)
    Dim topPanels As New ArrayList
    Dim bottomPanels As New ArrayList
    Dim middlePanel As ToolPanel
    Dim thisControl As ToolPanel
    Dim top As Boolean = True


    '------------------------------------------------------
    ' Loop threw the panel array and add the panels to the
    ' docking arrays.
    '
    For Each thisControl In Panels.ToArray
        If thisControl Is panel Then
            middlePanel = thisControl      ' Add the middle panel
            middlePanel.Maximize()
               ' Maximize the middle panel and redock
            top = False  ' Everything after this are bottom panels
        Else
            If top Then
                thisControl.Minimize(DockStyle.Top)
                       ' Minimize and redock
                topPanels.Add(thisControl)
                       ' Add the top panels
            Else
                thisControl.Minimize(DockStyle.Bottom)
                       ' Mimize and redock
                bottomPanels.Add(thisControl)
                       ' Add the bottom panels
            End If
        End If
    Next


    '------------------------------------------------------
    ' Add the panels to the control, be careful remember
    ' order is weird:
    '
    Me.Controls.Clear()         ' Clear out the controls
    topPanels.Reverse()         ' Reverse the top panel array
    Me.Controls.Add(middlePanel) ' Add the middle panel

    For Each thisControl In topPanels.ToArray
        Me.Controls.Add(thisControl)            ' Add the top
    Next

    For Each thisControl In bottomPanels.ToArray
        Me.Controls.Add(thisControl)            ' Add the Bottom
    Next

End Sub

What the remove function does is:

  • Create arrays for the top, middle and bottom panels
  • Loops the panels and puts them in there proper arrays
  • Clears out the controls
  • Adds the activeControl, a reversed version of the top controls and the bottom controls to the control. (Pay attention to the order the controls are added in)

ToolPanel Class

There is nothing real interesting in this class. It's main job is to draw the control and return it to the parent. It also has a bunch of properties and two methods. If you have any questions about this class please feel free to ask.

VB.NET
Public Class ToolPanel : Inherits Panel
    Private _Title As String
    Private _State As stateInfo = stateInfo.Maximized
    Private _Click As stateClick = stateClick.Normal
    Private _caption As New Rectangle
    Private _client As New Rectangle
    Private _captionSize As Integer = 20
    Private _parent As Toolbar.Initalize


    Sub New(ByVal name As String, ByVal sender As Toolbar.Initalize)
        Title = name
        _parent = sender

        Me.Dock = DockStyle.Fill                ' Make new panels filled
        Me.DockPadding.Top = _captionSize       ' Very important !
    End Sub


    '------------------------------------------------------
    ' *** A bunch of properties are here ***
    '------------------------------------------------------
    
    '------------------------------------------------------
    '          Sub: setAreas
    '  Description: Update the rectangle areas
    '
    Private Sub setAreas()
        _caption = New Rectangle(0, 0, Me.Width, captionHeight)
        _client = New Rectangle(0, Me.Top + captionHeight, 
                    Me.Width, Me.Height - captionHeight)
    End Sub


    '------------------------------------------------------
    '          Sub: Maximize
    '  Description: Change the state value and set the 
    '               toolpanel to fill
    '
    Public Sub Maximize()
        Me._State = stateInfo.Maximized
        Me.Dock = DockStyle.Fill
    End Sub

    '------------------------------------------------------
    '          Sub: Maximize
    '  Description: Change the state value and set the 
    '               toolpanel to whatever you sent me.
    '
    Public Sub Minimize(ByVal dock As DockStyle)
        Me._State = stateInfo.Minimized
        Me.Height = Me.captionHeight
        Me.Dock = dock
    End Sub

    '------------------------------------------------------
    '          Sub: ToolPanel_MouseDown
    '  Description: If they clicked in the captionarea then 
    '               change the click state
    '
    Private Sub ToolPanel_MouseDown(ByVal sender As Object, _
                      ByVal e As System.Windows.Forms.MouseEventArgs) _
                      Handles MyBase.MouseDown

        If e.Button = MouseButtons.Left Then
            If captionArea.IntersectsWith( _
                       New Rectangle(e.X, e.Y, 1, 1)) Then 
                Me._Click = stateClick.Clicked
                Invalidate(captionArea)
            End If
        End If
    End Sub

    '------------------------------------------------------
    '          Sub: ToolPanel_MouseUp
    '  Description: If the click state is clicked then call
    '               the view sub from the parent class
    '
    Private Sub ToolPanel_MouseUp(ByVal sender As Object, _
             ByVal e As System.Windows.Forms.MouseEventArgs) _
             Handles MyBase.MouseUp

        If e.Button = MouseButtons.Left And _Click = stateClick.Clicked Then
            Me._Click = stateClick.Normal
            Invalidate(captionArea)
            Me._parent.View(Me)
        End If
    End Sub

    '------------------------------------------------------
    '          Sub: ToolPanel_Paint
    '  Description: Redraw the controls
    '
    Private Sub ToolPanel_Paint(ByVal sender As Object, ByVal e As _
                 System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        setAreas()

        ' Get Colors and Pens
        '
        Dim captionFont As New Font(Me.Font, FontStyle.Regular)
        Dim captionBrush As Brush = _
             New SolidBrush(ColorTranslator.FromHtml("#ECE9D8"))
        Dim captionRect = New Pen(Color.White, 1)
        Dim captionPen = New Pen(Color.LightGray, 1)

        If _Click = stateClick.Clicked Then
            captionBrush = _
                  New SolidBrush(ColorTranslator.FromHtml("#D8EDEB"))
        End If

        ' Draw it
        '
        Dim g As Graphics = e.Graphics

        g.FillRectangle(captionBrush, captionArea)
        g.DrawRectangle(captionRect, captionArea)

        g.DrawLine(captionPen, _
                   New Point(captionArea.X + captionArea.Width - 1, _
                        captionArea.Y), _
                   New Point(captionArea.X + captionArea.Width - 1, _
                        captionArea.Y + captionArea.Height))

        g.DrawLine(New Pen(Color.Black, 2), _
                   New Point(captionArea.X, captionArea.Y + _
                     captionArea.Height), _
                   New Point(captionArea.Width, captionArea.Y + _
                     captionArea.Height))

        ' Draw Text
        '
        Dim textSize As SizeF = g.MeasureString(Title, captionFont)
        Dim textStart As Integer = (captionHeight / 2) - _
                (textSize.Height / 2)

        g.DrawString(Title, captionFont, Brushes.Black, Me.Left + 5, _
                  textStart)
    End Sub
End Class 

In a nutshell this class

  • Gets the information from the parent about what to create
  • Sets the dockpadding to the size of the header
  • Draws the control and maintains its state information
  • Handles mouse clicks and sends them back to the view function of the parent control

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I started programming for fun when I was about 10 on an Franklin Ace 1000.

I still do it just for fun but it has gotten me a few jobs over the years. More then I can say for my Microsoft Certifications. Smile | :)

The way I learned was by example, now its time to give back to the next generation of coders.



Comments and Discussions

 
QuestionAnimation? Pin
byy47g3s6t10-Jan-05 15:12
byy47g3s6t10-Jan-05 15:12 
GeneralAdd a collection.. Pin
RoyRose786-Sep-04 11:06
RoyRose786-Sep-04 11:06 
GeneralWon't work in my project. Pin
omlet211-Jul-04 14:58
omlet211-Jul-04 14:58 
GeneralNewbie Help! Pin
starbucket29-Jun-04 23:12
starbucket29-Jun-04 23:12 
GeneralExcellent! Pin
ABecerraSAP27-Apr-04 9:28
ABecerraSAP27-Apr-04 9:28 
GeneralRe: Excellent! Pin
Matthew Hazlett29-Apr-04 8:04
Matthew Hazlett29-Apr-04 8:04 
GeneralHmmm... Pin
David M. Kean14-Feb-04 13:59
David M. Kean14-Feb-04 13:59 
GeneralRe: Hmmm... Pin
Matthew Hazlett15-Feb-04 7:03
Matthew Hazlett15-Feb-04 7:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.