Download... the project. (12 kb)
If the listbox in VB1 to VB6 left you feeling constrained, you are not alone.
First of all, you couldn't have more than one font, more than one color, more than one anything.
So if you are in that camp, the possibilities in the .NET listbox are the coolest thing since
sliced cheese. In this article, I'll show you how to have one entry in the listbox have multiple colors.
The technique is pretty straightforward. First set the DrawMode of the listbox to OwnerDrawVariable. Then you must handle the DrawItem and MeasureItem events of the
ListBox and tell it what you want to draw. The Listbox fires these events for each item you draw. In addition,
these events will fire whenever the listbox repaints. In the MeasureItem event, you should tell it the height
of the text you are about to write. That's easy: instantiate the Graphics object and using its MeasureString method
figure out the height of the text.
Private Sub MeasureItemHandler(ByVal sender As Object, _
ByVal e As MeasureItemEventArgs) Handles lstColor.MeasureItem
Dim g As Graphics = Graphics.FromHwnd(lstColor.Handle)
Dim sf As StringFormat = New StringFormat(StringFormat.GenericTypographic)
Dim size As SizeF
Dim height As Single = 0
Dim oFont As New Font("Arial", 10)
'measure the height of what you are about to draw
'and let the listbox know this
size = g.MeasureString(data(e.Index), oFont, 500, sf)
height = size.Height + 5
e.ItemHeight = height
End Sub
All the action, however, occurs in the DrawItem event as this is where you actually draw the text.
In this case, we'll be drawing text of 2 different colors on the same line. You can draw just about anything
using this technique. So, as in the MeasureItem event, you must instantiate the Graphics object and
figure out the width of the first part of the text. Then using the Graphics.DrawString method, we draw
the actual text using whatever color we wish (created via the SolidBrush class). Pay particular attention
to the e.Bounds.X and e.Bounds.Y variables that are passed in as x and y.
They tell the listbox at what offset to start drawing relative to the
top left of the ListBox entry (not the ListBox itself.) This is very convinient, since we don't have to go
through calculation on where to start drawing for each item. Then we use the same Graphics.DrawString method
to draw the second part of the string in a different color. This time around we pass the Width of the first part of the
text as the x to avoid overlapping the text.
Private Sub DrawItemHandler(ByVal sender As Object, ByVal e As DrawItemEventArgs) _
Handles lstColor.DrawItem
Dim g As Graphics = Graphics.FromHwnd(lstColor.Handle)
Dim sf As StringFormat = New StringFormat(StringFormat.GenericTypographic)
Dim size As SizeF
Dim width As Single = 0
Dim oFont As New Font("Arial", 10)
'get the width of the string you are about to write
'this info is needed so that we can offset the next
'string that will be drawn in a different color.
size = g.MeasureString(data(e.Index), oFont, 500, sf)
width = size.Width + 16
'prepare the list for drawing
e.DrawBackground()
e.DrawFocusRectangle()
'draw the first string in a certain color
e.Graphics.DrawString(data(e.Index), oFont, _
New SolidBrush(color(e.Index)), e.Bounds.X, e.Bounds.Y)
'draw the second string in a different color
e.Graphics.DrawString(data(data.Length - 1 - e.Index), _
oFont, New SolidBrush(color(color.Length - 1 - e.Index)), width, e.Bounds.Y)
End Sub
And that's pretty much all there is to it. Using the same technique, you can draw whatever you want.
For instance, you can draw a pie. Go ahead and replace
e.Graphics.DrawString(data(data.Length - 1 - e.Index), oFont, _
New SolidBrush(color(color.Length - 1 - e.Index)), width, e.Bounds.Y)
with this:
e.Graphics.DrawPie(New Pen(System.Drawing.Color.Tomato), _
width, e.Bounds.Y, width, 10, 360, 270)
And you'll get a bunch of ugly looking pies, but you see the possibilities.