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 Constructor | Creates the ToolBar object |
ToolBar.count[ReadOnly] | Property | Returns the number of panels |
ToolBar.item(integer) | Property | Returns a panel object |
ToolBar.Remove(string) | Method | Removes a panel |
ToolBar.View(Object) | Method | Brings a panel into view |
ToolBar.Add(String) | Method | Adds a panel |
ToolPanel.new(String) | Constructor | Creates a ToolPanel object |
ToolPanel.Title[ReadOnly] | Property | Returns the Title |
ToolPanel.State[ReadOnly] | Property/Enum | Returns the object state |
ToolPanel.captionArea[ReadOnly] | Property | Returns a rectangle of the caption dimensions |
ToolPanel.clientArea[ReadOnly] | Property | Returns a rectangle of the client dimensions |
ToolPanel.captionHeight(integer) | Property | Returns/Sets the size of the caption |
ToolPanel.Maximize | Method | Although public do not call this, resets the docks |
ToolPanel.Minimize(Object) | Method | Although 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:
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:
Public Toolbar as new toolbar()
Now that you have created the object you can use it by calling toolbar.add("My Tab")
like this..
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:
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
Dim thisPanel As ToolPanel = Toolbar.add(TextBox.Text)
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
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:
Public Function add(ByVal name As String) As ToolPanel
MinimizeAll()
Dim newPanel = New ToolPanel(name, Me)
Panels.Add(newPanel)
Dim orderPanels As New ArrayList
Dim thisPanel As ToolPanel
For Each thisPanel In Panels.ToArray
orderPanels.Add(thisPanel)
Next
orderPanels.Reverse()
Me.Controls.Clear()
Me.Controls.Add(newPanel)
For Each thisPanel In orderPanels.ToArray
Me.Controls.Add(thisPanel)
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:
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
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
For Each thisControl In Panels.ToArray
If thisControl Is panel Then
middlePanel = thisControl
middlePanel.Maximize()
top = False
Else
If top Then
thisControl.Minimize(DockStyle.Top)
topPanels.Add(thisControl)
Else
thisControl.Minimize(DockStyle.Bottom)
bottomPanels.Add(thisControl)
End If
End If
Next
Me.Controls.Clear()
topPanels.Reverse()
Me.Controls.Add(middlePanel)
For Each thisControl In topPanels.ToArray
Me.Controls.Add(thisControl)
Next
For Each thisControl In bottomPanels.ToArray
Me.Controls.Add(thisControl)
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.
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
Me.DockPadding.Top = _captionSize
End Sub
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
Public Sub Maximize()
Me._State = stateInfo.Maximized
Me.Dock = DockStyle.Fill
End Sub
Public Sub Minimize(ByVal dock As DockStyle)
Me._State = stateInfo.Minimized
Me.Height = Me.captionHeight
Me.Dock = dock
End Sub
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
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
Private Sub ToolPanel_Paint(ByVal sender As Object, ByVal e As _
System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
setAreas()
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
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))
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