|
|
Make A Dockable Toolbar Like the Office Toolbar | | I need a toolbar to act like an Office Toolbar. How do I make a form resize and snap to the respective screen border as it moves outside of the bounds of the screen. I also need to relocate the buttons on the toolbar.
You would think this would be a simple task, and althought it is not rocket science, it does require some tricky code. If you do not get the code just right, you will get more "flash for the audience" than you want. For this reason, you will see a "Busy" flag being set that keeps the flash from happening. The Mosue_Move event will be firing so rapidily that you must protect the code that is moving the toolbar while it is in control. For this reason, if the truth were known, the Busy flag is causing me to ignore most of the Mouse_Move events. However, that will not be noticeable in the operation of moving the toolbar. This article will show you how to make a user designed toolbar automatically resize from a vertical to a horizontal position, relocate all of its tool buttons, and snap to the screen border as the toolbar is moved outside the bounds of the screen on any border.
First, you need to build a form like the one shown in Figure 1. The number of buttons is up to you. However they should all be the same size, including the lblMove Label, which has the move icon on it. The user must click on that control to move the form. Set the FormBorderStyle property to SizableToolWindow. If you use any one of the others, either it will not look good or it will not be able to be sized as narrow as I want it to be for a vertical toolbar.
Figure 1 - Docking Toolbar.

There are several sections of code that I will reproduce in the article so that you have all of the code, except for the Window Designer Code.
The declarations section of the form must have the variables shown below. I use the Enums so that I can get Intellisense and make the code more readable.
Private formLoading As Boolean = True
Private XPos As Long
Private YPos As Long
Private busy As Boolean
Private vWidth As Single = 32
Private vHeight As Integer = 160
Private hWidth As Integer = 160
Private hHeight As Integer = 32
Private btnHeight As Integer = 25
Private btnWidth As Integer = 25
Private currDockStyle As Short
Private Enum DockPosition
Top
Bottom
Left
Right
End Enum
Private Enum DockStyle
NotSet
Vertical
Horizontal
End Enum
|
The event handlers for the lblMove and mouse events are shown below. The Mouse_Move event determines when the toolbar has been moved outside of the bounds of the screen, on any of the four borders. When this happens, the DockToolBar method is called to snap the form to the border that the toobar has just violated.
Private Sub Form1_Resize(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Resize
' since only a few border styles will support a form as
' narrow as this one and sizable tool window is the best
' style to use, we must have a resize event in case the user
' has nothing else to do but to try to make the form look
' cruddy by resizing it, we force the size here...
If currDockStyle = DockStyle.NotSet Then
Exit Sub
ElseIf currDockStyle = DockStyle.Vertical Then
Me.Height = vHeight
Me.Width = vWidth
Else
Me.Height = hHeight
Me.Width = hWidth
End If
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button4.Click
Me.Dispose()
End Sub
Private Sub lblMove_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles lblMove.MouseDown
XPos = e.X
YPos = e.Y
End Sub
Private Sub lblMove_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles lblMove.MouseMove
Dim computedLeft As Single = Me.Left
Dim computedTop As Single = Me.Top
Dim computedRight As Single = (Me.Left + Me.Width)
Dim computedBottom As Single = (Me.Top + Me.Height)
If e.Button = MouseButtons.Left Then
If busy Then Exit Sub
busy = True
computedLeft = computedLeft - (XPos - e.X)
computedTop = computedTop - (YPos - e.Y)
computedRight = computedRight - (XPos - e.X)
computedBottom = computedBottom - (YPos - e.Y)
If computedLeft >= 1 And _
computedRight <= _<BR>
Screen.PrimaryScreen.Bounds.Width - 1 Then
Me.Left = Me.Left - (XPos - e.X)
Else
If Not computedLeft >= 1 Then
DockToolBar(DockPosition.Left)
Else
DockToolBar(DockPosition.Right)
End If
busy = True
Exit Sub
End If
If computedTop >= 1 And _
computedBottom <= _<BR>
Screen.PrimaryScreen.Bounds.Height - 1 Then
Me.Top = Me.Top - (YPos - e.Y)
Else
If Not computedTop >= 1 Then
DockToolBar(DockPosition.Top)
Else
DockToolBar(DockPosition.Bottom)
End If
busy = True
Exit Sub
End If
busy = False
End If
End Sub
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
currDockStyle = DockStyle.Horizontal
End Sub
Private Sub lblMove_MouseUp(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) _
Handles lblMove.MouseUp
busy = False
End Sub
|
The DockToolBar method does the actual work of redrawing the toolbar and relocating its constituent controls. The Mouse_Move event passes a parameter that tells the method what type of toolbar is to be drawn, vertical or horizontal, and the position that the redrawn toolbar is to take. You will notice that the code uses the Screen.PrimaryScreen.GetWorkingArea so that the TaskBar will be honored if AutoHide is not set.
Private Sub DockToolBar(ByVal DockTo As DockPosition)
Dim c As Control
Dim s As Single = 0
Dim i As Integer = 0
With Me
Dim pt As New System.Drawing.Point(Me.Left, Me.Top)
Select Case DockTo
Case DockPosition.Top, DockPosition.Bottom
Me.currDockStyle = DockStyle.Horizontal
' make the toolbar a horizontal bar
.Width = hWidth
.Height = hHeight
' relocate all controls except the move label
For Each c In Controls
If Not c Is lblMove Then
c.Top = 0
c.Left = (i * (btnWidth + 5))
i += 1
DoEvents()
End If
Next
Me.lblMove.Left = Me.Width - (25 + 5)
.lblMove.Top = 0
DoEvents()
' honor the taskbar if not auto hidden
If DockTo = DockPosition.Top Then
.Top = 1
Else
.Top = Screen.PrimaryScreen.GetWorkingArea(pt).Height - _
(.Height + 1)
End If
.Left = Math.Min(.Left, _
Screen.PrimaryScreen.GetWorkingArea(pt).Width - _
(.Width + 1))
Case DockPosition.Left, DockPosition.Right
currDockStyle = DockStyle.Vertical
' redraw the form as vertical toolbar
.Width = vWidth
.Height = vHeight
' relocate all of the controls except the move label
For Each c In Controls
If Not c Is lblMove Then
c.Left = 0
c.Top = (i * (btnHeight + 5))
i += 1
DoEvents()
End If
Next
' relocate the move label
.lblMove.Left = 0
.lblMove.Top = .Height - (25 + 5)
' this code honors any on top task bar if not auto hidden
If DockTo = DockPosition.Left Then
.Left = 1
Else
.Left = Screen.PrimaryScreen.GetWorkingArea(pt).Width - _
(.Width + 1)
End If
.Top = Math.Min(.Top, _
Screen.PrimaryScreen.GetWorkingArea(pt).Height - _
(.Height + 1))
End Select
End With
End Sub
|
As the toolbar is dragged toward a screen border, and crosses the border, it will automatically morph from Vertical to Horizontal as shown in Figure 2 and Figure 3.
Figure 2 - Horizontal Toolbar.

Figure 3 - Vertical Toolbar.

Top Of Form |
|