I have seen a lot of programmers putting a StatusBar control to their main form and never using it. Are you one of these? In this column, I’ll show you some nice features (icons, back color setting, buttons, combos, progress bar) you can add to a StatusBar, that are requiring some code (but not that much).
The basics
By default, the StatusBar presents a single panel at the bottom of form. Do you know that a status bar can be located elsewhere? Since it is a regular control, it has the Dock property.
SizingGrip is a property specific to the StatusBar. When this property is set to True, the StatusBar displays small diagonal lines at the lower-right corner of the control to cue the user that the form is resizable (notice that you have to set it – this property is not automatically set depending on the FormBorderStyle property).
This default appearance looks more like a label then anything else. To set a value to this label-replacement, just set the Text property:
StatusBar1.Text = “Hello World!”
Instead of using the StatusBar as a replacement for the Label control, we typically set the ShowPanels property to True. Instead of having one large label, we now have has many panels as we want.
Panels can be created at design-time or at run-time (like much anything else in .Net). There is not much to do with the designer of this control. Yes you can add panels but features are quite limited from the “StatusBarPanel Collection editor”.
Figure 1: The StatusBarPanel Collection editor
Each panel has some properties, to which you are surely used to (like Alignment, Text, Width, …) so I want explained them. Other properties are more specific to the panels:
Those who read me regularly know that I’m not a big fan of setting properties at design time. So as usual, I will use code to create my panels and everything else.
The demo application
As advertised in the introduction, we will customize a status bar so it will look like this.
Figure 2: The demo application
I will not copy the complete source code here (only important parts) so I invite you to use the link at the bottom of this column to download the demo application.
Adding an Icon
Lets start with an easy task: adding (and removing) an icon from a panel of the status bar. First we need to add a new panel. This code is normally executed when a form loads. So this code creates a new instance of the StatusBarPanel class, set some properties (no trace of the icon yet) and add it to the status bar (I suppose you have a status bar named StatusBar1 with no properties set on your form).
Dim pnlX As StatusBarPanel With StatusBar1 'Icon panel pnlX = New StatusBarPanel With pnlX .Alignment = HorizontalAlignment.Center .AutoSize = StatusBarPanelAutoSize.None .BorderStyle = StatusBarPanelBorderStyle.Sunken .Width = 30 End With .Panels.Add(pnlX) .SizingGrip = True .ShowPanels = True End With
If btnImage.Tag Is Nothing Then btnImage.Tag = "" End If If btnImage.Tag.ToString = "IMAGE" Then StatusBar1.Panels(MyPanels.pnlIcon).Icon = Nothing btnImage.Text = "Display Icon" btnImage.Tag = "" Else StatusBar1.Panels(MyPanels.pnlIcon).Icon = _ New System.Drawing.Icon("c:\W95MBX01.ICO") btnImage.Text = "Hide Icon" btnImage.Tag = "IMAGE" End If
Changing the back color of a panel
You may want to change the back color of one of the panel as a visual cue for the user. Since there is no property for this, we have to find another method to handle it.
Once again we need some code to add a panel to host it:
pnlX = New StatusBarPanel With pnlX .AutoSize = StatusBarPanelAutoSize.None .BorderStyle = StatusBarPanelBorderStyle.Sunken .Style = StatusBarPanelStyle.OwnerDraw .Text = "Colored text" .Width = 100 End With .Panels.Add(pnlX)
sbdevent.Graphics.FillRectangle(New SolidBrush(mclrSelectedColor), sbdevent.Bounds) Dim sf As New StringFormat sf.Alignment = StringAlignment.Center sf.LineAlignment = StringAlignment.Center sbdevent.Graphics.DrawString(sbdevent.Panel.Text, _ StatusBar1.Font, _ New SolidBrush(Color.Black), _ New RectangleF(sbdevent.Bounds.X, _ sbdevent.Bounds.Y, _ sbdevent.Bounds.Width, _ sbdevent.Bounds.Height), _ sf)
Detecting a click on a panel
You may want to detect when a user click on a particular panel of your status bar. For panels like the 2 we just added, there are no problems. The PanelClick event of the status bar is raised for that. For panels that will host controls (buttons, combos, …) it is more difficult because the click event of the control is raised (instead of the PanelClick event). One of the arguments sent by the PanelClick event lets us determines which panel was clicked:
Select Case StatusBar1.Panels.IndexOf(e.StatusBarPanel) Case MyPanels.pnlIcon MessageBox.Show("Panel = Icon") Case MyPanels.pnlProgressBar MessageBox.Show("Panel = Progress bar") Case MyPanels.pnlTextColor MessageBox.Show("Panel = Text Color") Case MyPanels.pnlProgressPanel MessageBox.Show("Panel = Another Progress bar") End Select
Hosting a Button control
Typically, a status bar is passive control but nothing stops you from having it accepting user interaction. In this example, we will add a button to a panel of the status bar. First, we need to add the panel and its button:
pnlX = New StatusBarPanel With pnlX .AutoSize = StatusBarPanelAutoSize.None .BorderStyle = StatusBarPanelBorderStyle.Sunken .Style = StatusBarPanelStyle.OwnerDraw .Width = 100 End With .Panels.Add(pnlX) Me.Controls.Add(mctlButton) mctlButton.Text = "Try me!" mctlButton.Parent = StatusBar1 AddHandler mctlButton.Click, AddressOf ButtonClickTest
Private Sub ButtonClickTest(ByVal sender As System.Object, _ ByVal e As System.EventArgs) MessageBox.Show("Are you really surprised to see me!!!") End Sub
Case MyPanels.pnlButtton With mctlButton .Location = New Point(sbdevent.Bounds.X, sbdevent.Bounds.Y) .Size = New Size(sbdevent.Bounds.Width, sbdevent.Bounds.Height) .Show() End With
Hosting a ComboBox control
Hosting a combo or almost any other control is not different then a button like we did in the previous example so I will not copy the code here (but you have a working example in the downloadable demo).
Hosting a progress bar control
How hosting a progress bar is different from a button? From the initialization and the drawing of the control, there are no differences. The difference comes from the fact that the panel needs to be repainted on some events like the tick of a timer to indicate a new progress value. So here is the code I have in the Tick event of a timer control:
If mctlProgressBar.Value < 10 Then mctlProgressBar.Value += 1 StatusBar1.Invalidate() Else Timer1.Enabled = False End If
Another way of showing the progress
The downloadable demo proposes another method of displaying a progress bar in a panel that does not require the use of the ProgressBar control. Its surface is also a solid block and even the percentage is written into the panel.
Conclusion
Implementing a useful StatusBar requires some code but finally we can use it for more then a label replacement.
If anyone is making a subclass control from it, please send it to me!
I hope you appreciated the topic and see you next month.