logo
vbRad Home
Source Code
Book Reviews
Forum
Links
About Us
Contribute

Compare Databases with SQL Effects Clarity
 
 Owner-drawn listbox with multiple colors in the same line

Posted on
6/21/2004
Author:
Robert Gelb
Email:
Not Shown
Applies To OS:
Windows
Product:
.NET Framework



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.





Add Your Comment  

Name: Email Address: all fields optional
Notify me via email when someone responds to this message (valid email required).

Enter the word:
 



Comments
#1. By Anonymous. Posted on 4/26/2006 2:09:15 PM
tyty

#2. By Rajesh. Posted on 11/23/2007 3:38:49 PM
Cool

C# version possible to post?

#3. By Anonymous. Posted on 11/26/2007 5:18:12 PM
To #2. Google for vb.net to c# conversion