Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Textbox with rounded corners

0.00/5 (No votes)
1 Feb 2007 1  
A TextBox control with rounded corners.

Sample image

Introduction

I've been looking around a bit to find an example of how to get a Windows Forms TextBox painted with rounded corners, but I did not find a solution. I collected some useful tips, put them all together with some logic, and came up with a satisfying solution. Because I have found many excellent coding tips on this site, I'm posting the source here so it hopefully can be useful for someone.

Overview

To come up with the rounded corners textbox, I started trying to work with the paint override event, but unfortunately without any result, which is due to the fact (I assume) that the textbox is derived from Windows. Therefore, I tried overriding the WM_PAINT API instead, which had the desired results.

The tricky part then was that I first could only draw on the client area of the textbox, which resulted in a very small textbox. Once again, API came up with a solution: I added two declarations, one for GetWindowDC to get a handle on the non-client area, and one for ReleaseDC to clean up after my custom drawing.

Now that I could fully use the graphics of my textbox, and added the coding to draw a rounded rectangle, I was still not completely satisfied because the height of my textbox was dependent on the font size. I tried searching a way to override this "hidden" autosize event, but did not find a working solution. I came up with a way to be able to change the textbox's height by setting the multiline feature to true, but I still believe there has to be a better way for this. Because I also added a method which catches the Enter-keypress and which returns a Tab-keypress instead, the multiline solution will do for my needs.

Because the rounded textbox control is part of a bigger solution I recently wrote, you will also find some custom properties, OriText, NewText, and a custom event Texthaschanged, which actually is a way to check whether the control text has changed before the Onleave-event takes place, and the custom properties provide access to the original text as well as the new text. I needed these properties and left them in the control, maybe someone finds them useful.

The code

OK, time for the code.

The procedure below handles the event of pressing the Enter key, as well as the event of pressing the "," key. The Enter key has been replaced by a Tab key so the next control in the tab order will be selected. The second part of the procedure is to handle the input of a decimal character and format the input according to Belgian point for decimal format.

Protected Overrides Function ProcessCmdKey(ByRef msg _
                    As System.Windows.Forms.Message, _
                    ByVal keyData As System.Windows.Forms.Keys) As Boolean 
    If msg.WParam.ToInt32() = CInt(Keys.Enter) Then 
        SendKeys.Send("{Tab}")
        Return True 
    ElseIf msg.WParam.ToInt32() = CInt(Keys.Decimal) Then 
        SendKeys.Send(",")
        Return True 
    End If 
End Function

The next method is the actual overriding of the WM_Paint event, in which the redrawing is done. It makes uses of the API functions GetWindowDC and ReleaseDC to get the actual graphics of the control, including the non-client area.

Protected Overrides Sub WndProc(ByRef m As _
          System.Windows.Forms.Message) Handles MyBase.WndProc(m)
    Select Case m.Msg
        Case &HF 'WM_PAINT 
            Dim rect As New Rectangle(0, 0, MyBase.Width, MyBase.Height)
            Dim hDC As IntPtr = GetWindowDC(Me.Handle)
            Dim g As Graphics = Graphics.FromHdc(hDC)
            If Me.Enabled Then 
                g.Clear(Color.White)
            Else 
                g.Clear(Color.FromName("control"))
            End If 
            DrawBorder(g)
            DrawText(g)
            ReleaseDC(Me.Handle, hDC)
            g.Dispose()
        Case &H7, &H8, &H200, &H2A3
        'CMB_DROPDOWN, CMB_CLOSEUP, WM_SETFOCUS, 
        'WM_KILLFOCUS, WM_MOUSEMOVE, 'WM_MOUSELEAVE 
            UpdateState()
    End Select 
End Sub

To get the rounded corners, the method shown below is used.

Private Sub TekenRondeRechthoek(ByVal g As Graphics, _
            ByVal pen As Pen, ByVal rectangle As Rectangle, _
            ByVal radius As Single)
    Dim size As Single = (radius * 2.0!)
    Dim gp As GraphicsPath = New GraphicsPath
    gp.AddArc(rectangle.X, rectangle.Y, size, size, 180, 90)
    gp.AddArc((rectangle.X + (rectangle.Width - size)), _
               rectangle.Y, size, size, 270, 90)
    gp.AddArc((rectangle.X + (rectangle.Width - size)), _
              (rectangle.Y + (rectangle.Height - size)), _
              size, size, 0, 90)
    gp.AddArc(rectangle.X, (rectangle.Y + _
             (rectangle.Height - size)), size, size, 90, 90)
    gp.CloseFigure()
    g.DrawPath(pen, gp)
    gp.Dispose()
End Sub

The complete code example is included in the attached zip-file. I hope it can be useful for anyone.

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