Click here to Skip to main content
15,891,033 members
Articles / Programming Languages / Visual Basic
Article

Flatten that Combobox!

Rate me:
Please Sign up or sign in to vote.
4.24/5 (19 votes)
2 Feb 20035 min read 276.7K   3.5K   25   36
A flat style combobox in VB.NET

Flatten That Combobox

In .NET, Microsoft has given us many things to work with. It's nice how they standardized properties like Text and Name on most controls. However, what's the story with the flat look?

Some controls have a flat look as a property, either through the FlatStyle property or the Border property. I love the flat look and have been using it for all my controls, except one. The combobox. Do you know how funny a data entry form looks when all its text boxes, checkboxes, radio buttons, command buttons, etc are flat, but its combo boxes are 3D? You probably do, and that's why you're looking here...

This project is nothing more than a simple combobox that inherits from combobox. All events and properties of the regular combo box are there. It even does data binding. The great thing is that it's flat.

The flat look is accomplished by subclassing, a cool OO concept that old VB developers new to VB.NET are just getting used to. There are 6 overridden methods:

VB
Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
Protected Overrides Sub OnLostFocus(ByVal e As System.EventArgs)
Protected Overrides Sub OnGotFocus(ByVal e As System.EventArgs)
Protected Overrides Sub OnMouseHover(ByVal e As System.EventArgs)
Protected Overrides Sub WndProc(ByRef m As Message)

The focus and enter methods all do pretty much the same thing. They call MyBase.OnMethod (which, amongst other things, is responsible for raising the proper events), set the color of the brush we will use to paint the background, and call Me.Invalidate(), which causes the control to repaint.

The real work is done by the WndProc method. For some reason that I have not figured out yet, the combobox does not call OnPaint in the base class. The control is actually drawn using windows messages. I used a Select Case to evaluate the message. Case &HF (15) is the value for the paint method. It comes from the windows message constant WM_PAINT.

Once we capture the WM_PAINT message, the work can begin. I simply color the background color according to the color that was set by one of the events mentioned earlier. (For example, OnGotFocus sets the color to SystemColors.Highlight, which is found in the System.Drawing namespace). I do this by creating a handle to a Graphics object and calling the FillRectangle method.

VB
Dim g As Graphics = Me.CreateGraphics
g.FillRectangle(BorderBrush, Me.ClientRectangle)

The base class will draw an edit box on top of this background fill, giving a highlighted effect to the control. The next thing is to draw the rectangle for the dropdown button. This will always have a fixed width and location, relevant to the width of the combobox control. This is how the base control works, and it also makes locating the drawing area of the dropdown arrow much easier.

VB
Dim rect As Rectangle = New Rectangle(Me.Width - 15, 3, 12, _
                                      Me.Height - 6)
      g.FillRectangle(DropButtonBrush, rect)

The last thing to do is to draw the dropdown arrow. This is done by creating a path and filling it. The Drawing2D.GraphicsPath object serves as a way to draw lines in a “freestyle” manner. These lines will always be connected. The path will always close itself in a straight line from the last mapped point to the first point. It’s kind of like drawing with an old etch-a-sketch where the pen never leaves the drawing surface. For this reason, to draw a triangle, it is only necessary to draw 2 lines.

What I did in the code below is declare the 3 points on the triangle (relative to the vertical middle of the control). Then I draw 2 lines. One line runs from top left to top right, and the other from the top right to the bottom.

VB
Dim pth As Drawing2D.GraphicsPath = New Drawing2D.GraphicsPath()
Dim TopLeft As PointF = New PointF(Me.Width - 13, (Me.Height - 5) / 2)
Dim TopRight As PointF = New PointF(Me.Width - 6, (Me.Height - 5) / 2)
Dim Bottom As PointF = New PointF(Me.Width - 9, (Me.Height + 2) / 2)

pth.AddLine(TopLeft, TopRight)
pth.AddLine(TopRight, Bottom)

I then set the smoothing mode property of the graphics object so that the triangle will look crisper.

VB
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality

Whenever we fill something, we need to use a Brush. The signature of the Fill methods ask for a Brush, but you cannot create an instance of Brush. The Brush class is abstract, meaning it must be inherited to be used. What to do? The best bet for a solid fill is to use the SolidBrush class. This can be tough to figure out, as it was for me when I was first starting with GDI+.

To determine the color to fill the triangle with, I check the DroppedDown property. I noticed on the combobox control, the arrow is 2 different colors, depending on if it is dropped down or not.

VB
If Me.DroppedDown Then
    ArrowBrush = New SolidBrush(SystemColors.HighlightText)
Else
    ArrowBrush = New SolidBrush(SystemColors.ControlText)
End If

Finally, it is time to fill the triangle.

VB
g.FillPath(ArrowBrush, pth)

Voila! There you have it. A flat combobox. I added a property to the control for button color, so the artsy GUI designers can have more flexibility. It’s code is straight forward for the most part, but I did want to point out something about the property set statement.

VB
Public Property ButtonColor() As Color
    Get
        Return _ButtonColor
    End Get
    Set(ByVal Value As Color)
        _ButtonColor = Value
        DropButtonBrush = New SolidBrush(Me.ButtonColor)
        Me.Invalidate()
    End Set
End Property

Notice the call to Me.Invalidate(). This causes the control to repaint itself. Now, at design time, when the property is changed, the designer will show the new button color.

Short and sweet this project is. There are several good things to learn out of it though. Drawing custom controls using GDI+ and subclassing are 2 very important things to learn in .NET. I hope this article helps you to understand the breakdown of the code behind the FlatCombo, as well as helped to give you some more understanding about these important concepts.

I had previously done this project as a conversion from a C# project I found. If you download the source code, you will see the old version. It had a few quirky bugs around the way that it drew. It was also way overcomplicated. I thought I would leave it behind incase you wanted to see a different solution.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Malaysia Malaysia
As an experienced programmer, I know how hard it is to find good code sometimes. I hope my articles and samples are as good for you as they are for me. Need more good code? Email me.

Comments and Discussions

 
QuestionHow do you add the flatcombo to the controls toolbox? Pin
domfos31-Mar-03 12:20
domfos31-Mar-03 12:20 
AnswerRe: How do you add the flatcombo to the controls toolbox? Pin
IbanezPlayer31-Mar-03 14:39
IbanezPlayer31-Mar-03 14:39 
Questionhow to bind data with textbox after executing search query thru code? Pin
drmzunlimited25-Sep-02 12:10
drmzunlimited25-Sep-02 12:10 
AnswerRe: how to bind data with textbox after executing search query thru code? Pin
Anonymous27-Dec-02 10:56
Anonymous27-Dec-02 10:56 
GeneralOld style dropdown still showes. Pin
Ronny18-Jun-02 12:44
Ronny18-Jun-02 12:44 
GeneralRe: Old style dropdown still showes. Pin
Anonymous2-Jan-03 12:33
Anonymous2-Jan-03 12:33 
GeneralRe: Old style dropdown still showes. Pin
IbanezPlayer2-Jan-03 15:46
IbanezPlayer2-Jan-03 15:46 
GeneralRe: Old style dropdown still showes. Pin
IamLamb5-Aug-04 13:13
IamLamb5-Aug-04 13:13 
Hi,

I followed your link but unfortunately it's broken. Can you forward me your source code for this?

kelvinandrews@hotmail.com

Would be appreciated.
QuestionWhy? Pin
Ray Hayes14-Jun-02 0:47
Ray Hayes14-Jun-02 0:47 
AnswerRe: Why? Pin
IbanezPlayer17-Jun-02 15:43
IbanezPlayer17-Jun-02 15:43 
GeneralRe: Why? Pin
blong11-Jul-02 15:28
blong11-Jul-02 15:28 
GeneralRe: Why? Pin
TigerNinja_27-Aug-02 12:00
TigerNinja_27-Aug-02 12:00 
GeneralRe: Why? Pin
OnlineNoob27-Dec-03 1:51
OnlineNoob27-Dec-03 1:51 
GeneralRe: Why? Pin
tidoy14-Jan-04 4:50
tidoy14-Jan-04 4:50 
GeneralRe: Why? Pin
IbanezPlayer28-Jan-04 17:10
IbanezPlayer28-Jan-04 17:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.