Riples
Riples

Reputation: 1157

Issue Drawing Rounded Corners On Custom Control

I am trying to create a custom control that resembles a long rectangle with rounded corners and a border. It will also contain some text, an icon and so forth, but I am having issues with the manual drawing of the control when added programmatically to my form.

The code looks like so:

Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices
Imports Transitions
Imports System.Drawing.Drawing2D

Public Class AlertPanel

    Private m_Radius As Integer
    Private m_BorderWidth As Integer
    Private m_AlertType As AlertType
    Private m_Icon As Image

    ''' <summary>
    ''' Indicates a Radius of the control's corners
    ''' </summary>
    ''' <returns>The corner Radius.</returns>
    Public Property Radius As Integer
        Get
            Return m_Radius
        End Get
        Set(value As Integer)
            m_Radius = value
        End Set
    End Property

    ''' <summary>
    ''' Indicates the width to draw the outer border of the control.
    ''' </summary>
    ''' <returns>The border width.</returns>
    Public Property BorderWidth As Integer
        Get
            Return m_BorderWidth
        End Get
        Set(value As Integer)
            m_BorderWidth = value
        End Set
    End Property

    ''' <summary>
    ''' Indicates the type of Alert for the control.
    ''' </summary>
    ''' <returns>The Alert type.</returns>
    Public Property AlertType As AlertType
        Get
            Return m_AlertType
        End Get
        Set(value As AlertType)
            m_AlertType = value
        End Set
    End Property

    Public Sub New()

        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

    End Sub

    Private Sub AlertPanel_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim rect As Rectangle = Me.ClientRectangle 'Drawing Rounded Rectangle
        rect.X = rect.X + 1
        rect.Y = rect.Y + 1
        rect.Width -= 2
        rect.Height -= 2

        Using bb As GraphicsPath = GetPath(rect, Radius)
            'Draw the background
            Using br As Brush = New SolidBrush(BackColor)
                e.Graphics.SmoothingMode = SmoothingMode.HighQuality
                e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
                e.Graphics.FillPath(br, bb)
            End Using
            'Draw the border
            Using br As Brush = New SolidBrush(ForeColor)
                rect.Inflate(-1, -1)
                e.Graphics.SmoothingMode = SmoothingMode.HighQuality
                e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
                e.Graphics.DrawPath(New Pen(br, BorderWidth), bb)
            End Using
        End Using
    End Sub

    Protected Function GetPath(ByVal rc As Rectangle, ByVal r As Int32) As GraphicsPath
        Dim x As Int32 = rc.X, y As Int32 = rc.Y, w As Int32 = rc.Width, h As Int32 = rc.Height
        r = r << 1
        Dim path As GraphicsPath = New GraphicsPath()
        If r > 0 Then
            If (r > h) Then r = h
            If (r > w) Then r = w
            path.AddArc(x, y, r, r, 180, 90)
            path.AddArc(x + w - r, y, r, r, 270, 90)
            path.AddArc(x + w - r, y + h - r, r, r, 0, 90)
            path.AddArc(x, y + h - r, r, r, 90, 90)
            path.CloseFigure()
        Else
            path.AddRectangle(rc)
        End If
        Return path
    End Function

End Class

Then I call it like this:

Dim a As New AlertPanel
            With a
                .Size = New Size(400, 60)
                .Location = New Point(100, 200)
                .AlertType = AlertType.Major
                .ForeColor = Color.Black
                .BorderWidth = 1
                .BackColor = Color.IndianRed
                .Radius = 10
            End With
            Me.Controls.Add(a)

And I am left with this:

enter image description here

UPDATE

After some edits to my code as per Plutonix below, I now have the following results:

enter image description here

FINAL UPDATE

Final result looks like below. Many thanks to Plutonix for all the help!

enter image description here

Upvotes: 1

Views: 2171

Answers (3)

Ollie Turner
Ollie Turner

Reputation: 1

I got rounded corners on a button control using a function that's called during the paint event.

  1. Must have visual studio, create a new project
  2. Select a new windows form as your new project
  3. Add 2 x buttons to the form
  4. Double click anywhere on the form to open up the code window
  5. Delete all of the code, including the Form1 sub headers, and paste in the below


Imports System.Drawing.Drawing2D


Public Class Form1

    Public Sub buttonBorderRadius(ByRef buttonObj As Object, ByVal borderRadiusINT As Integer)
        Dim p As New Drawing2D.GraphicsPath()
        p.StartFigure()
        'TOP LEFT CORNER
        p.AddArc(New Rectangle(0, 0, borderRadiusINT, borderRadiusINT), 180, 90)
        p.AddLine(40, 0, buttonObj.Width - borderRadiusINT, 0)
        'TOP RIGHT CORNER
        p.AddArc(New Rectangle(buttonObj.Width - borderRadiusINT, 0, borderRadiusINT, borderRadiusINT), -90, 90)
        p.AddLine(buttonObj.Width, 40, buttonObj.Width, buttonObj.Height - borderRadiusINT)
        'BOTTOM RIGHT CORNER
        p.AddArc(New Rectangle(buttonObj.Width - borderRadiusINT, buttonObj.Height - borderRadiusINT, borderRadiusINT, borderRadiusINT), 0, 90)
        p.AddLine(buttonObj.Width - borderRadiusINT, buttonObj.Height, borderRadiusINT, buttonObj.Height)
        'BOTTOM LEFT CORNER
        p.AddArc(New Rectangle(0, buttonObj.Height - borderRadiusINT, borderRadiusINT, borderRadiusINT), 90, 90)
        p.CloseFigure()
        buttonObj.Region = New Region(p)
    End Sub



    Private Sub Button1_Paint(sender As Object, e As PaintEventArgs) Handles Button1.Paint
        buttonBorderRadius(sender, 25)
    End Sub

    Private Sub Button2_Paint(sender As Object, e As PaintEventArgs) Handles Button2.Paint
        buttonBorderRadius(sender, 50)
    End Sub


End Class

Calling the function buttonBorderRadius(sender, 50) means you can set different borderRadius's for individual buttons. And because it uses the object, you can apply the same function to pictureboxes, and other controls (not all though).

So you can set a 10 pixel border radius with buttonBorderRadius(sender, 10) and a 50 pixel radius like this buttonBorderRadius(sender, 50) just change the integer as the 2nd argument in the function, and the 1st argument has to be the object variable.

Upvotes: 0

Prakash
Prakash

Reputation: 100

Public Sub ctrlCornerBorder(ctrl As Control, CurveSize As Integer)

    Try

        Dim p As New System.Drawing.Drawing2D.GraphicsPath

        p.StartFigure()
        p.AddArc(New Rectangle(0, 0, CurveSize, CurveSize), 180, 90)
        'p.AddLine(CurveSize, 0, ctrl.Width - CurveSize, 0)

        p.AddArc(New Rectangle(ctrl.Width - CurveSize, 0, CurveSize, CurveSize), -90, 90)
        'p.AddLine(ctrl.Width, CurveSize, ctrl.Width, ctrl.Height - CurveSize)

        p.AddArc(New Rectangle(ctrl.Width - CurveSize, ctrl.Height - CurveSize, CurveSize, CurveSize), 0, 90)
        'p.AddLine(ctrl.Width - 40, ctrl.Height, 40, ctrl.Height)

        p.AddArc(New Rectangle(0, ctrl.Height - CurveSize, CurveSize, CurveSize), 90, 90)
        p.CloseFigure()

        ctrl.Region = New Region(p)
        p.Dispose()

    Catch ex As Exception
        MsgBox(Err.Number & vbCrLf & Err.Description, MsgBoxStyle.Information)
    End Try

Put This As A Class file And call Like This as Follows...

ctrlCornerBorder(pnlList, 15).

Here ctrlCornerBorder is our Class File name and pnlList As our Panel Name And 15 is value to be change as per your need to make curvy edge on panel...

Upvotes: 0

I am trying to create a custom control You didnt say whether this was subclassing a control (like Panel) or was built as a UserControl. I am guessing the latter based on InitializeComponent().

The main thing seems to be that the standard Border for the UserControl is still being painted. Add this to turn it off:

Public Sub New()
    MyBase.BorderStyle = Windows.Forms.BorderStyle.None
    ...

You may want to hide that property so the end user cant turn it back on in Properties.

Also, with wider borders you will find that the bottom border is being clipped by one pixel (somewhat apparent in your image - the top horizontal appears thicker than the bottom one). Add this to your GetPath method:

h As Int32 = rc.Height - 1

Result:

enter image description here

Also, BackColor is inherited and applies to the entire client area, which remains a rectangle. You'll probably need to replace that as well. Leave the actual BackColor as Transparent, maybe hiding it that property from the user as well, and use a new FillColor property:

' in the paint event
Using br As Brush = New SolidBrush(FillColor)
   ...

Using a FillColor property and forcing BackColor to Transparent:

enter image description here

Upvotes: 2

Related Questions