locked
How to make smooth round ellipse form? RRS feed

  • Question

  • I have a form that I made round by the following code:

      Private Sub DrawEllipse(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            'Me.BackColor = Color.Red
            Dim gp As New Drawing2D.GraphicsPath
            Dim top As Integer = SystemInformation.SizingBorderWidth + 1 + SystemInformation.CaptionHeight
            Dim left As Integer = SystemInformation.SizingBorderWidth + 1
            gp.AddEllipse(New Rectangle(left, top, Me.ClientSize.Width, Me.ClientSize.Height))
            Me.Region = New Region(gp)
    
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            Using Pen1 As New Pen(Brushes.Blue, 20)
                e.Graphics.DrawEllipse(Pen1, 1, 1, Me.ClientSize.Width, Me.ClientSize.Height)
            End Using
        End Sub

    But if you try this code, you will notice that it don't have a smooth circle,so I want it to be a perfect round circle form.

    So how?

    Saturday, February 1, 2014 2:36 PM

Answers

  • The problem is that clipping regions are made up of rectangles. Antialiasing modifies the pixels outside of the edges, but it can't do that if those pixels have been removed. Pixels are square so you will always have jagged edges if cutting pixels out.

    Are there going to be any controls on your form?

    If the answer is no then you want to search for "per pixel alpha form"

    If the answer is yes then things become much more complicated. There is an example on my form tips page: http://dotnetrix.co.uk/form.htm#tip7 but another option is to have two forms; one for the alpha blended background and one for the controls, which get moved together. The previous search should find you examples of this.


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:11 PM
    • Unmarked as answer by Titanium man11 Thursday, February 6, 2014 5:11 PM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:12 PM
    Sunday, February 2, 2014 12:21 PM
  • The simple answer is that you need to work within the constraints of GDI+.

    When the transparency is simulated, the effect uses only a single color and is applied to whole pixels so there are limits to how "smooth" the effect will be.  To achieve the greatest possible result, you'll need to use finely-crafted source images that are designed to minimize the limitations.  Sticking to sharp lines and not allowing any blur on the pen is one tip.  Another common way to get around the issue is to include a black stroke around the outside edge of each shape; then a black transparency will typically smooth out nicely.

    If you need a more dazzling visual effect, move to a WPF or Silverlight project where the rendering is done with 3D acceleration instead of with old-fashioned GDI.

    Here's a simple example of what is about "as good as it gets" for GDI.  Note the different shapes in the image have varying degrees of "smoothness" depending on the angle and brush of the lines.

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            BackColor = Color.Black
            TransparencyKey = Color.Black
            Size = My.Resources.ExampleForm.Size
            BackgroundImage = My.Resources.ExampleForm
            FormBorderStyle = Windows.Forms.FormBorderStyle.None
        End Sub
    End Class


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    • Edited by Reed KimbleMVP Tuesday, February 4, 2014 6:27 PM typo
    • Proposed as answer by tommytwotrain Wednesday, February 5, 2014 12:19 AM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:12 PM
    Tuesday, February 4, 2014 6:26 PM
  • Unfortunately, since you are going to have controls, this has become a lot more complicated.

    Using a Layered Window will get you the drawing results that you are looking for, but Layered windows will only paint what you instruct them how to paint. They completely ignore the standard windows paint messages.

    Your options at this point are:

    1. As Reed Kimble suggests, migrate to WPF.

    2. Draw controls yourself instead of adding controls. Not much fun if you need textboxes or similar, but simple buttons and labels are no problem.

    3. Use the Layered Window as the background and then create a second form to contain the controls and move this with the Layered Window. (That's another question for you to raise should you choose this method).

    Here is the code for a layered window:

    Imports System.Runtime.InteropServices
    Imports System.Drawing.Imaging
    Imports System.Drawing.Drawing2D
    
    Partial Public Class Form1
    
        Public Sub New()
            InitializeComponent()
        End Sub
    
        Protected Overrides ReadOnly Property CreateParams() As CreateParams
            Get
                Dim cp As CreateParams = MyBase.CreateParams
                If Not Me.DesignMode Then
                    cp.ExStyle = cp.ExStyle Or NativeMethods.WS_EX_LAYERED
                End If
                Return cp
            End Get
        End Property
    
        Protected Overrides Sub OnResize(ByVal e As EventArgs)
            MyBase.OnResize(e)
            If Me.Created Then
                UpdateWindow()
            End If
        End Sub
    
        Protected Overrides Sub OnLocationChanged(ByVal e As EventArgs)
            MyBase.OnLocationChanged(e)
            If Me.Created Then
                UpdateWindow()
            End If
        End Sub
    
        Protected Overrides Sub OnVisibleChanged(ByVal e As EventArgs)
            MyBase.OnVisibleChanged(e)
            If Me.Visible Then
                UpdateWindow()
            End If
        End Sub
    
        Public Sub UpdateWindow()
    
            If Me.IsDisposed OrElse Me.Width <= 0 OrElse Me.Height <= 0 Then
                Return
            End If
    
            Dim borderWidth As Int32 = 24
    
            Using backBuffer As New Bitmap(Me.Width, Me.Height, PixelFormat.Format32bppPArgb)
    
                Using gr As Graphics = Graphics.FromImage(backBuffer)
    
                    gr.SmoothingMode = SmoothingMode.AntiAlias
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality
                    gr.CompositingQuality = CompositingQuality.GammaCorrected
                    gr.CompositingMode = CompositingMode.SourceOver
    
                    Dim rc As Rectangle = Me.Bounds
                    rc.Offset(-Me.Left, -Me.Top)
                    rc.Inflate(-borderWidth / 2, -borderWidth / 2)
    
                    If rc.Width > 0 AndAlso rc.Height > 0 Then
    
                        Using linGrBrush As New LinearGradientBrush(rc, Color.Blue, Color.Red, LinearGradientMode.ForwardDiagonal)
                            gr.FillEllipse(linGrBrush, rc)
                        End Using
    
                        Using myPen As New Pen(Color.SteelBlue, borderWidth)
                            gr.DrawEllipse(myPen, rc)
                            myPen.Color = Color.LightSteelBlue
                            myPen.Width = 2
                            rc.Inflate(-borderWidth / 2, -borderWidth / 2)
                            gr.DrawEllipse(myPen, rc)
                        End Using
    
                    End If
    
                    'Use Interop to transfer the bitmap to the screen.
                    Dim screenDC As IntPtr = NativeMethods.GetDC(IntPtr.Zero)
                    Dim memDC As IntPtr = NativeMethods.CreateCompatibleDC(screenDC)
                    Dim hBitmap As IntPtr = backBuffer.GetHbitmap(Color.FromArgb(0))
                    Dim oldBitmap As IntPtr = NativeMethods.SelectObject(memDC, hBitmap)
    
                    Dim blend As New NativeMethods.BLENDFUNCTION(255)
                    Dim ptDst As Point = Me.Location
                    Dim szDst As Size = backBuffer.Size
                    Dim ptSrc As Point = Point.Empty
                    NativeMethods.UpdateLayeredWindow(Me.Handle, screenDC, ptDst, szDst, memDC, ptSrc, 0, blend, NativeMethods.ULW_ALPHA)
    
                    NativeMethods.SelectObject(memDC, oldBitmap)
                    NativeMethods.DeleteObject(hBitmap)
                    NativeMethods.DeleteDC(memDC)
                    NativeMethods.DeleteDC(screenDC)
    
                End Using
    
            End Using
    
        End Sub
    
    End Class
    
    Public Class NativeMethods
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Friend Shared Function UpdateLayeredWindow(ByVal hwnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As Point, ByRef psize As Size, ByVal hdcSrc As IntPtr, ByRef pptSrc As Point, ByVal crKey As Int32, ByRef pblend As BLENDFUNCTION, ByVal dwFlags As Int32) As Boolean
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Friend Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function CreateCompatibleDC(ByVal dc As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hObj As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function DeleteDC(ByVal dc As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function DeleteObject(ByVal hObj As IntPtr) As IntPtr
        End Function
    
        <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Friend Structure BLENDFUNCTION
            Public BlendOp, BlendFlags, SourceConstantAlpha, AlphaFormat As Byte
            Public Sub New(ByVal alpha As Byte)
                Me.BlendOp = AC_SRC_OVER
                Me.BlendFlags = 0
                Me.SourceConstantAlpha = alpha
                Me.AlphaFormat = AC_SRC_ALPHA
            End Sub
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Friend Structure RECT
            Public Left, Top, Right, Bottom As Int32
        End Structure
    
        Friend Const WS_EX_LAYERED As Int32 = &H80000
        Friend Const AC_SRC_OVER As Int32 = &H0
        Friend Const AC_SRC_ALPHA As Int32 = &H1
        Friend Const ULW_ALPHA As Int32 = &H2
    
    End Class

    and this is how it looks:


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com


    • Edited by Mick Doherty Tuesday, February 4, 2014 7:44 PM
    • Proposed as answer by tommytwotrain Tuesday, February 4, 2014 11:13 PM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:13 PM
    Tuesday, February 4, 2014 7:40 PM
  • just to let you know well what I meant, if you look to your second picture you posted, notice the inner circle(the blue border), inside the form the ellipse is perfect,while the outer circle(of the blue) is rough,noticed?

    Maybe this is better?

    Private Sub DrawEllipse(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint

    'put these 3 lines in the form load event
    'make it whatever size, I added my border size to 400 Me.TransparencyKey = Me.BackColor Me.Width = 416 Me.Height = 438 Dim cx, cy, r As Integer Dim borderx As Single = Me.Width - Me.ClientSize.Width Dim bordery As Single = Me.Height - Me.ClientSize.Height r = (Me.Width / 2) - (bordery + 2) cx = (Me.Width / 2) - r cy = (Me.Height / 2) - r Dim rect As Rectangle = New Rectangle(borderx / 2, bordery - (borderx / 2), Me.ClientSize.Width - borderx, Me.ClientSize.Height - bordery) Me.Region = New Region(rect) Dim Pen1 As New Pen(Brushes.Blue, 12) e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias e.Graphics.FillEllipse(Brushes.Yellow, cx - borderx / 2, cy - (bordery - (borderx / 2)), 2 * r - 10, 2 * r - 10)
    'an ellipse may work fine here as well e.Graphics.DrawArc(Pen1, cx - (2 + borderx / 2), cy - (2 + bordery - (borderx / 2)), (2 * r) - 10, (2 * r) - 10, 0, 360)

    End Sub







    Saturday, February 1, 2014 7:53 PM

All replies

  • Using an arc is a little better? You also have to account for the header I guess.

        Private Sub DrawEllipse(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            Dim cx, cy, r As Integer
            r = (Me.ClientSize.Width / 2) - 40  'account for header
            cx = (Me.ClientSize.Width / 2) - r
            cy = (Me.ClientSize.Height / 2) - r
    
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    
            Dim gp As New Drawing2D.GraphicsPath
            'Dim top As Integer = SystemInformation.SizingBorderWidth + 1 + SystemInformation.CaptionHeight
            'Dim left As Integer = SystemInformation.SizingBorderWidth + 1
            'gp.AddEllipse(New Rectangle(left, top, Me.ClientSize.Width, Me.ClientSize.Height))
    
            gp.AddArc(cx, cy, 2 * r, 2 * r, 0, 360)
            Me.Region = New Region(gp)
    
    
    
            Using Pen1 As New Pen(Brushes.Blue, 12)
                'e.Graphics.DrawEllipse(Pen1, 1, 1, Me.ClientSize.Width - 10, Me.ClientSize.Height - 10)
    
                e.Graphics.DrawArc(Pen1, cx - 3, cy - 25, (2 * r) - 10, (2 * r) - 10, 0, 360)
    
            End Using
        End Sub
    End Class



    • Edited by tommytwotrain Sunday, February 2, 2014 2:34 AM combine
    Saturday, February 1, 2014 3:51 PM
  • It's still the  same,I don't know if you understood me precisely,I mean there are circles that are very smooth and not rough, I want to make exactly as they are. 
    Saturday, February 1, 2014 4:50 PM
  • I discovered that it's because of the form's ellipse and not the other one(the border),so we have to make the form's border as smooth.So any idea?

    And to understand what I mean, draw the border inside the form, to see how smooth it is.

    Saturday, February 1, 2014 5:07 PM
  • I discovered that it's because of the form's ellipse and not the other one(the border),so we have to make the form's border as smooth.So any idea?

    And to understand what I mean, draw the border inside the form, to see how smooth it is.

    Show us a picture of the one that works how you want and where it comes from. I was going by your example.

    But, I know what you mean. I am still looking at it. I wrestle with this for my CAD program. I think it may just be how well it works using what we are using. I have noticed that if the circle is small you get more jagged and if large the aliasing works better. I also suspect that the region for the form may not be aliasing because its outside the drawing area. It may be that drawing your own circle with points is better. I have been trying making the form transparent and then drawing everything but no better. I guess that is why your question. So I will keep quiet now unless I find something better. I suspect a couple other forum members may be looking too? Lets see what they come up with.

    :)

    Saturday, February 1, 2014 5:19 PM
  • just to let you know well what I meant, if you look to your second picture you posted, notice the inner circle(the blue border), inside the form the ellipse is perfect,while the outer circle(of the blue) is rough,noticed?
    Saturday, February 1, 2014 5:46 PM
  • just to let you know well what I meant, if you look to your second picture you posted, notice the inner circle(the blue border), inside the form the ellipse is perfect,while the outer circle(of the blue) is rough,noticed?

    Maybe this is better?

    Private Sub DrawEllipse(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint

    'put these 3 lines in the form load event
    'make it whatever size, I added my border size to 400 Me.TransparencyKey = Me.BackColor Me.Width = 416 Me.Height = 438 Dim cx, cy, r As Integer Dim borderx As Single = Me.Width - Me.ClientSize.Width Dim bordery As Single = Me.Height - Me.ClientSize.Height r = (Me.Width / 2) - (bordery + 2) cx = (Me.Width / 2) - r cy = (Me.Height / 2) - r Dim rect As Rectangle = New Rectangle(borderx / 2, bordery - (borderx / 2), Me.ClientSize.Width - borderx, Me.ClientSize.Height - bordery) Me.Region = New Region(rect) Dim Pen1 As New Pen(Brushes.Blue, 12) e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias e.Graphics.FillEllipse(Brushes.Yellow, cx - borderx / 2, cy - (bordery - (borderx / 2)), 2 * r - 10, 2 * r - 10)
    'an ellipse may work fine here as well e.Graphics.DrawArc(Pen1, cx - (2 + borderx / 2), cy - (2 + bordery - (borderx / 2)), (2 * r) - 10, (2 * r) - 10, 0, 360)

    End Sub







    Saturday, February 1, 2014 7:53 PM
  • PS the clipping region for the outside form edge does not get anti-aliasing apparently. Its not a drawing surface I guess. So by making the form transparent we only see the blue edge that we draw with anti-aliasing .


    PSS I also used only even numbers to help things be symmetric.
    Saturday, February 1, 2014 8:02 PM
  • Well my last example has little remnants still showing through around the outside edge I did not notice on a white background. Here is about the best I can find. Hope it helps.

    I used a gradient brush to hide some of the problems from my previous example. I did away with the border circle. Changed the form background to the same color we draw with.

    Imports System.Drawing.Drawing2D
    Public Class Form6
    
        Private Sub Form6_Load(sender As Object, e As EventArgs) Handles Me.Load
            Me.BackColor = Color.Blue
            Me.TransparencyKey = Me.BackColor
            Me.Width = 400
            Me.Height = 400
    
        End Sub
        Private Sub DrawEllipse(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
            Dim cx, cy, r As Integer
            Dim borderx As Single = Me.Width - Me.ClientSize.Width
            Dim bordery As Single = Me.Height - Me.ClientSize.Height
    
            r = (Me.Width / 2) - (bordery + 2)
            cx = (Me.Width / 2) - r
            cy = (Me.Height / 2) - r
    
            Dim rect As Rectangle = New Rectangle(borderx / 2, bordery - (borderx / 2), Me.ClientSize.Width - borderx, Me.ClientSize.Height - bordery)
            Me.Region = New Region(rect)
    
            Dim linGrBrush As New LinearGradientBrush(New Point(0, 0), New Point(Me.ClientSize.Width, Me.ClientSize.Height), Color.Blue, Color.White)
    
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            e.Graphics.FillEllipse(linGrBrush, cx - borderx / 2, cy - bordery, 2 * r, 2 * r)
    
        End Sub
    


    • Edited by tommytwotrain Saturday, February 1, 2014 9:52 PM more tweeking
    Saturday, February 1, 2014 9:25 PM
  • I just added all this stuff in my forms paint event. It seems to have cleaned up the top, bottom, left and right edges of the circle. I believe the composting stuff cleaned it up the most. You can try commenting out some of the other stuff and see how it affects the circle.

    I didn't dispose of the brush or pen as I should have since I was just testing.

    Option Strict On
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.DoubleBuffered = True
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
            e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
            e.Graphics.CompositingMode = CompositingMode.SourceOver
            Dim Brush1 As New SolidBrush(Color.Black)
            Dim Pen1 As New Pen(Brush1, 20)
            e.Graphics.DrawEllipse(Pen1, 50, 50, 200, 200)
        End Sub
    
    End Class


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.

    Saturday, February 1, 2014 11:33 PM
  • Unfortunately when I tested the new code in the Forms paint event with your code that makes the round form it didn't work out. So I believe that drawing to the screen over the form will correct that.

    I have code that I used to do that for something. And I have the move, resize and other events from some other project that take that stuff into account. It detects if the desktop refreshes also and repaints the drawing. But I think if it's not the top most form it doesn't draw so as not to draw over some other form.

    I'll post something later tonight or tomorrow morning.

    This is what I just tested though.

    Option Strict On
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        Dim ABordersWidth As Integer = 0
        Dim TitlebarHeight As Integer = 0
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.DoubleBuffered = True
            ABordersWidth = CInt((Me.Width - Me.ClientSize.Width) / 2)
            TitlebarHeight = Me.Height - Me.ClientSize.Height - 2 * ABordersWidth
        End Sub
    
        Dim MyLeft As Integer = 0
        Dim MyTop As Integer = 0
    
        Private Sub DrawEllipse() Handles MyBase.Paint
            Dim gp As New Drawing2D.GraphicsPath
            MyTop = SystemInformation.SizingBorderWidth + 1 + SystemInformation.CaptionHeight
            MyLeft = SystemInformation.SizingBorderWidth + 1
            gp.AddEllipse(New Rectangle(MyLeft, MyTop, Me.ClientSize.Width, Me.ClientSize.Height))
            Me.Region = New Region(gp)
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
            e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
            e.Graphics.CompositingMode = CompositingMode.SourceOver
            Using Pen1 As New Pen(Brushes.Black, 8)
                e.Graphics.DrawEllipse(Pen1, MyLeft - ABordersWidth, MyTop - TitlebarHeight - ABordersWidth, Me.ClientSize.Width, Me.ClientSize.Height)
            End Using
        End Sub
    
    End Class
    

    Image from test isn't good like my previous posts drawing became.


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.

    Saturday, February 1, 2014 11:50 PM
  • Monkey,

    Note how your inside edge is smooth. The outside edge made to the form by the region is jagged. That's the problem area.

    Sunday, February 2, 2014 12:22 AM
  • Welp, no matter what I use it always seems to leave a jagged edge on the outside. I have done away with the region to just use a transparent form thinking at least it is drawing with anti-aliasing, still debating if it improves anything. One also must be careful about the background colors. In this example it looks good on the left but fuzzy on the right.

    Imports System.Drawing.Drawing2D
    Public Class Form6
        Private Sub Form6_Load(sender As Object, e As EventArgs) Handles Me.Load
            Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
            Me.BackColor = Color.Blue
            Me.TransparencyKey = Me.BackColor
    
        End Sub
        Private Sub Form6_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            Dim thesize As Single
            If Me.Width > Me.Height Then thesize = Me.Height Else thesize = Me.Width
    
            Dim r As Single = ((thesize / 2) - 4)
            Dim cx As Single = (Me.Width / 2) - r
            Dim cy As Single = (Me.Height / 2) - r
    
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    
            'form fill
            Dim linGrBrush As New LinearGradientBrush(New Point(0, 0), New Point(Me.ClientSize.Width, Me.ClientSize.Height), Color.Blue, Color.White)
            e.Graphics.FillEllipse(linGrBrush, cx, cy, 2 * r, 2 * r)
            'border inside
            e.Graphics.DrawEllipse(New Pen(Color.SteelBlue, 6), cx + 3, cy + 3, 2 * r - 6, 2 * r - 6)
            'border outside
            e.Graphics.DrawEllipse(New Pen(Color.LightSteelBlue, 2), cx, cy, 2 * r - 1, 2 * r - 1)
    
        End Sub
    End Class

    Sunday, February 2, 2014 1:31 AM
  • Yep. That's why I figure drawing to the screen over the form will work instead of drawing to the form. But it results in a headache for all the other stuff you have to take into account. :(

    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.

    Sunday, February 2, 2014 2:50 AM
  • While I was searching the code project, I found an unanswered thread, but honestly I understood nothing,so I hope you see it  Here, and what do you think of this solution?

    And another thing, tommytwotrain's solution(the one with yellow form and blue border) seems 

     to be the best for now.
    Sunday, February 2, 2014 9:18 AM
  • I some how got it,first what I should say that I apparently don't have much skills in this field(Drawing)

    but while I was trying and experimenting I got an idea that i hope you would help me with.

    Note: the FormBorderStyle is set to None

    First if we only draw a border(yellow one),without drawing the form and set the transparencyKey to background then we will have a yellow loop only.But if we made this loop (made it a complete circle) then we will obtain a circle(so it would be the circle form).But what about making borders?Heh,now this point is simple,if we make the color of the yellow circle as Gradient,but circular one then we may obtain a border and a form from one drawn circle.

    So can someone approve my theory ;-),and provide me with the code for achieving so?

    Sunday, February 2, 2014 10:56 AM
  • The problem is that clipping regions are made up of rectangles. Antialiasing modifies the pixels outside of the edges, but it can't do that if those pixels have been removed. Pixels are square so you will always have jagged edges if cutting pixels out.

    Are there going to be any controls on your form?

    If the answer is no then you want to search for "per pixel alpha form"

    If the answer is yes then things become much more complicated. There is an example on my form tips page: http://dotnetrix.co.uk/form.htm#tip7 but another option is to have two forms; one for the alpha blended background and one for the controls, which get moved together. The previous search should find you examples of this.


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:11 PM
    • Unmarked as answer by Titanium man11 Thursday, February 6, 2014 5:11 PM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:12 PM
    Sunday, February 2, 2014 12:21 PM
  • I some how got it,first what I should say that I apparently don't have much skills in this field(Drawing)

    but while I was trying and experimenting I got an idea that i hope you would help me with.

    Note: the FormBorderStyle is set to None

    First if we only draw a border(yellow one),without drawing the form and set the transparencyKey to background then we will have a yellow loop only.But if we made this loop (made it a complete circle) then we will obtain a circle(so it would be the circle form).But what about making borders?Heh,now this point is simple,if we make the color of the yellow circle as Gradient,but circular one then we may obtain a border and a form from one drawn circle.

    So can someone approve my theory ;-),and provide me with the code for achieving so?

    Yes you are describing it correctly. However, using the same color in the tranparancy that we draw with does not help much. I tried the circular gradient last night it is the same problem. I looked at the link you gave it is the same. Same same same. Mick D is also right. Only Monkey's idea is different. Lets see if he tried it.

    Imports System.Drawing.Drawing2D
    Public Class Form6
        Private Sub Form6_Load(sender As Object, e As EventArgs) Handles Me.Load
            Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
            Me.BackColor = Color.Blue
            Me.TransparencyKey = Me.BackColor
    
        End Sub
        Private Sub Form6_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            Dim thesize As Single
            If Me.Width > Me.Height Then thesize = Me.Height Else thesize = Me.Width
    
            'circle radius
            Dim r As Single = ((thesize / 2) - 4)
            'corner coordinates to center the circle
            Dim cx As Single = (Me.Width / 2) - r
            Dim cy As Single = (Me.Height / 2) - r
    
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    
            ' Create a path that consists of a single ellipse. 
            Dim path As New GraphicsPath()
            path.AddEllipse(cx, cy, 2 * r, 2 * r)
    
            ' Use the path to construct a brush. 
            Dim pthGrBrush As New PathGradientBrush(path)
    
            ' Set the color at the center of the path to blue.
            pthGrBrush.CenterColor = Color.White
    
            ' Set the color along the entire boundary  
            ' of the path to aqua. 
            Dim colors As Color() = {Color.DarkBlue}
            pthGrBrush.SurroundColors = colors
    
            e.Graphics.FillEllipse(pthGrBrush, cx, cy, 2 * r, 2 * r)
            e.Graphics.DrawEllipse(New Pen(Color.SteelBlue, 6), cx + 3, cy + 3, 2 * r - 6, 2 * r - 6)
        End Sub
    End Class
    

    Sunday, February 2, 2014 2:43 PM
  • While I was searching the code project, I found an unanswered thread, but honestly I understood nothing,so I hope you see it  Here, and what do you think of this solution?

    And another thing, tommytwotrain's solution(the one with yellow form and blue border) seems 

     to be the best for now.

    My yellow background example is the same problem. If you put it against a dark background you see little white dots around the edges. It is the same as my other examples. The last solution with the circular gradient is the same. It has been optimized a bit and works for any size form etc. So that one or the diagonal gradient fill is best (same). I changed to a horizontal fill and that looks best to my eye, but the edges are all the same.

            'horz form fill
            Dim rect As New Rectangle(0, 0, Me.ClientSize.Width, Me.ClientSize.Height)
            Dim linGrBrush As New LinearGradientBrush(rect, Color.Blue, Color.White, -90)
            e.Graphics.FillEllipse(linGrBrush, cx, cy, 2 * r, 2 * r)
            'border 
            e.Graphics.DrawEllipse(New Pen(Color.SteelBlue, 6), cx + 3, cy + 3, 2 * r - 6, 2 * r - 6)
    

    Sunday, February 2, 2014 2:55 PM
  • Whoops, where did you go? Well I wrote this so here it is.

    I think I did what you  asked but maybe I don't understand. So perhaps you should do it. I think we have given you the code that you can tweek. Then I think you will see. I think I know what you are describing and I think if you will run it yourself you will see. You have to put the form on both a light and dark background. If you are drawing dark it looks good on dark but jagged on light. That's why my last pics have both. I have tried what you suggest it is all the SAME. The outside edge is jagged no matter what you draw it with.

        "Because I see no circular gradient."

    Its a couple of examples up. If I understand. If not show us what you mean. That is best. You try it. Then you will understand it. Use my last examples, very easy.

    Sunday, February 2, 2014 3:38 PM
  • PS In my last example, if you comment out the transparency in the form load, the outside edge is smooth. Of course then you see the outside form. Turn on the transparency and the outside edge is jagged. I suspect that deep in the bowels of the vb it is just clipping to make the transparency and that is what we did with the clipping region. Its not a drawing surface I guess. It is not Anti-Aliasing because that must use the background color that is next to what we draw. When we clip or go transparent it cant do that because there is no color next to what we draw. Just my theory, someone else probably knows the details better than I.
    Sunday, February 2, 2014 3:53 PM
  • I thought I deleted this comment(me second one),since after I posted I tried it and the same bad result.That's the reason I deleted it.

    For now I'll wait a little if someone shows up and solves it,and if not then I'll mark yours as anserws

    Sunday, February 2, 2014 5:49 PM
  • Well I drew an ellipse to the screen and none of the code that I used to create the ellipse seemed to smooth out the edges like the image in my post where I used the following code.

    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
    e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
    e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
    e.Graphics.CompositingMode = CompositingMode.SourceOver
    

    Also I drew an ellipse on the screen around the round form and because the form is then inside the drawing area a label I was using to show the current cursor location on screen was not updating until the next screen paint event occured which would cause the screen to refresh basically.


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.

    Monday, February 3, 2014 12:13 AM
  • This code uses a borderless Form with a transparent background and fills the majority of the form except the parts you can see in the first pic in the image below before the transparencykey is turned on in the second pic in the image below.

    The edges look pretty clean. The minimize and close buttons are drawn on the Form.

    I didn't expend the time and energy for determining from the drawn ellipses where to locate the minimize and close buttons drawn on the form. I just moved them around bit by bit till the numbers worked.

    The last part I was working on was drawing curved text (Form1) to add in the border area at the top of the form. But I haven't finished that yet.

    Option Strict On
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        'The region of the minimum button.
        Private miniBoxRect As Rectangle
        'The region of the close button.
        Private closeBoxRect As Rectangle
        'The states of the two header buttons.
        Private miniState As ButtonState
        Private closeState As ButtonState
        'The size of the header buttons.
        ReadOnly BUTTON_BOX_SIZE As Size = New Size(12, 12)
    
        'Store the mouse down points to handle moving the form.
        Private x As Integer = 0
        Private y As Integer = 0
    
        Dim FormsOrigBackColor As Color = Color.Black ' Give it a default color for now.
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.DoubleBuffered = True
            Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
            Me.Size = New Size(300, 300)
            FormsOrigBackColor = Me.BackColor ' Get forms original backcolor before changing it.
            Button1.Left = CInt((Me.Width / 2) - (Button1.Width / 2)) ' Center Button1 on Form.
            Button1.Top = CInt((Me.Height / 2) - (Button1.Height / 2)) ' Center Button1 on Form.
            Me.BackColor = Color.PapayaWhip
            Me.TransparencyKey = Color.PapayaWhip
            miniBoxRect = New Rectangle(Me.Width - 95, 20, BUTTON_BOX_SIZE.Width, BUTTON_BOX_SIZE.Height)
            closeBoxRect = New Rectangle(Me.Width - 65, 40, BUTTON_BOX_SIZE.Width, BUTTON_BOX_SIZE.Height)
        End Sub
    
        Dim CurvedStringFont As New Font("Garamond", 8) ' This is not being used yet.
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
            e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
            e.Graphics.CompositingMode = CompositingMode.SourceOver
            Dim MidPointXLeft As Integer = Button1.Left + CInt(Button1.Width / 2) ' Get Midpoint of Button1s width (Could've done for Form instead).
            Dim MidPointYTop As Integer = Button1.Top + CInt(Button1.Height / 2) ' Get Midpoint of Button1s height  (Could've done for Form instead).
            Using Brush1 As New SolidBrush(FormsOrigBackColor)
                Using Pen1 As New Pen(Brush1, 1)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 24, MidPointYTop - CInt(Me.Height / 2) + 24, CInt(Me.Width) - 48, CInt(Me.Height) - 48)
                    e.Graphics.FillEllipse(Brush1, MidPointXLeft - CInt(Me.Width / 2) + 24, MidPointYTop - CInt(Me.Height / 2) + 24, CInt(Me.Width) - 48, CInt(Me.Height) - 48)
                End Using
            End Using
            ' At this point still have 24 pixels to left, right, top and bottom edge of Form to draw in for border stuff.
            Using Brush1 As New SolidBrush(Color.Black)
                Using Pen1 As New Pen(Brush1, 2)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 22, MidPointYTop - CInt(Me.Height / 2) + 22, CInt(Me.Width) - 44, CInt(Me.Height) - 44)
                End Using
            End Using
            ' Just used 2 pixels to draw ellipse outside of original ellipse.
            Using Brush1 As New SolidBrush(FormsOrigBackColor)
                Using Pen1 As New Pen(Brush1, 20)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 11, MidPointYTop - CInt(Me.Height / 2) + 11, CInt(Me.Width) - 22, CInt(Me.Height) - 22)
                End Using
            End Using
            ' Used 22 pixels to draw ellipse outside of above ellipse.
            Using Brush1 As New SolidBrush(Color.Black)
                Using Pen1 As New Pen(Brush1, 2)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 1, MidPointYTop - CInt(Me.Height / 2) + 1, CInt(Me.Width) - 2, CInt(Me.Height) - 2)
                End Using
            End Using
            ' Used up the last 2 pixels.
    
    
            'Draw the header buttons.
            If Me.MinimizeBox Then
                ControlPaint.DrawCaptionButton(e.Graphics, miniBoxRect, CaptionButton.Minimize, miniState)
            End If
            If Me.MinimizeBox Then
                ControlPaint.DrawCaptionButton(e.Graphics, closeBoxRect, CaptionButton.Close, closeState)
            End If
    
    
    
            ' The below code was going to be used to draw a curved string in the "border" around the Form.
    
            'Dim text As String = "Form1"
    
            'Dim Test() As PointF = {New PointF(0, 0), New PointF(160, 0), New PointF(160, 200), New PointF(80, 150), New PointF(0, 200)}
    
            'Dim textPath As New GraphicsPath(Test, Int64)
    
            'Dim textBounds As RectangleF = textPath.GetBounds()
    
            'textPath.AddString(text, System.Drawing.FontFamily.GenericSansSerif, 1, 8, New Point(0, 0), System.Drawing.StringFormat.GenericDefault)
    
            'e.Graphics.DrawPath(Pens.Black, textPath)
    
        End Sub
    
        Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
            'Start to move the form.
            If (Me.ClientRectangle.Contains(e.Location)) Then
                x = e.X
                y = e.Y
            End If
    
            'Check and press the header buttons.
            Dim mousePos As Point = Me.PointToClient(Control.MousePosition)
            If (miniBoxRect.Contains(mousePos)) Then
                miniState = ButtonState.Pushed
            ElseIf (closeBoxRect.Contains(mousePos)) Then
                closeState = ButtonState.Pushed
            End If
        End Sub
    
        Private Sub CustomBorderColorForm_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
            'Move and refresh.
            If (x <> 0 And y <> 0) Then
                Me.Location = New Point(Me.Left + e.X - x, Me.Top + e.Y - y)
                Me.Refresh()
            End If
        End Sub
    
        Private Sub CustomBorderColorForm_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
            'Reset the mouse point.
            x = 0
            y = 0
    
            'Check the button states and modify the window state.
            If miniState = ButtonState.Pushed Then
                Me.WindowState = FormWindowState.Minimized
                miniState = ButtonState.Normal
            ElseIf closeState = ButtonState.Pushed Then
                Me.Close()
            End If
        End Sub
    
    End Class


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.



    Monday, February 3, 2014 3:51 AM
  • Just a question, what is the purpose of

    Dim rect As Rectangle = New Rectangle(borderx / 2, bordery - (borderx / 2), Me.ClientSize.Width - borderx, Me.ClientSize.Height - bordery)
    Me.Region = New Region(rect)

    Monday, February 3, 2014 6:03 PM
  • Another question,is that can't we draw our form from point zero?
    Monday, February 3, 2014 6:04 PM
  • Another thing Monekyboy, is that you are putting the form on a white background, and just I want you to note that putting the frm on a white background won't show the jagged frm surface.
    Monday, February 3, 2014 6:24 PM
  • You still haven't answered a very critical question.

    Is your form going to contain controls?


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    Monday, February 3, 2014 6:45 PM
  • Another thing Monekyboy, is that you are putting the form on a white background, and just I want you to note that putting the frm on a white background won't show the jagged frm surface.

    Yes, its the same basic problem, same basic method. This example does not use the draw to screen idea Monkey proposed. Have you looked at what Mick D is suggesting?

    Monday, February 3, 2014 7:25 PM
  • Another thing Monekyboy, is that you are putting the form on a white background, and just I want you to note that putting the frm on a white background won't show the jagged frm surface.

    Yes, its the same basic problem, same basic method. This example does not use the draw to screen idea Monkey proposed. Have you looked at what Mick D is suggesting?

    I didn't notice that. Below is the best that I can get it which is a bit better than what's above.

    Option Strict On
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        'The region of the minimum button.
        Private miniBoxRect As Rectangle
        'The region of the close button.
        Private closeBoxRect As Rectangle
        'The states of the two header buttons.
        Private miniState As ButtonState
        Private closeState As ButtonState
        'The size of the header buttons.
        ReadOnly BUTTON_BOX_SIZE As Size = New Size(12, 12)
    
        'Store the mouse down points to handle moving the form.
        Private x As Integer = 0
        Private y As Integer = 0
    
        Dim FormsOrigBackColor As Color = Color.Black ' Give it a default color for now.
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
            Me.DoubleBuffered = True
            Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
            Me.Size = New Size(304, 304)
            FormsOrigBackColor = Me.BackColor ' Get forms original backcolor before changing it.
            Button1.Left = CInt((Me.Width / 2) - (Button1.Width / 2)) ' Center Button1 on Form.
            Button1.Top = CInt((Me.Height / 2) - (Button1.Height / 2)) ' Center Button1 on Form.
            Me.BackColor = Color.PapayaWhip
            Me.TransparencyKey = Color.PapayaWhip
            miniBoxRect = New Rectangle(Me.Width - 109, 20, BUTTON_BOX_SIZE.Width, BUTTON_BOX_SIZE.Height)
            closeBoxRect = New Rectangle(Me.Width - 75, 40, BUTTON_BOX_SIZE.Width, BUTTON_BOX_SIZE.Height)
        End Sub
    
        Dim CurvedStringFont As New Font("Garamond", 8) ' This is not being used yet.
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    
            Dim MidPointXLeft As Integer = Button1.Left + CInt(Button1.Width / 2) ' Get Midpoint of Button1s width (Could've done for Form instead).
            Dim MidPointYTop As Integer = Button1.Top + CInt(Button1.Height / 2) ' Get Midpoint of Button1s height  (Could've done for Form instead).
    
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
            e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
            e.Graphics.CompositingMode = CompositingMode.SourceOver
            
            Using Brush1 As New SolidBrush(FormsOrigBackColor)
                Using Pen1 As New Pen(Brush1, 1)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 28, MidPointYTop - CInt(Me.Height / 2) + 28, CInt(Me.Width) - 56, CInt(Me.Height) - 56)
                    e.Graphics.FillEllipse(Brush1, MidPointXLeft - CInt(Me.Width / 2) + 28, MidPointYTop - CInt(Me.Height / 2) + 28, CInt(Me.Width) - 56, CInt(Me.Height) - 56)
                End Using
            End Using
            ' At this point still have 24 pixels to left, right, top and bottom edge of Form to draw in for border stuff.
            Using Brush1 As New SolidBrush(Color.Black)
                Using Pen1 As New Pen(Brush1, 2)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 27, MidPointYTop - CInt(Me.Height / 2) + 27, CInt(Me.Width) - 54, CInt(Me.Height) - 54)
                End Using
            End Using
    
            ' Just used 2 pixels to draw ellipse outside of original ellipse.
            Using Brush1 As New SolidBrush(Color.DodgerBlue)
                Using Pen1 As New Pen(Brush1, 20)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 16, MidPointYTop - CInt(Me.Height / 2) + 16, CInt(Me.Width) - 32, CInt(Me.Height) - 32)
                End Using
            End Using
    
            ' Used 22 pixels to draw ellipse outside of above ellipse.
            Using Brush1 As New SolidBrush(Color.Black)
                Using Pen1 As New Pen(Brush1, 2)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 6, MidPointYTop - CInt(Me.Height / 2) + 6, CInt(Me.Width) - 12, CInt(Me.Height) - 12)
                End Using
            End Using
            'Used up the last 2 pixels.
    
            'Draw the header buttons.
            If Me.MinimizeBox Then
                ControlPaint.DrawCaptionButton(e.Graphics, miniBoxRect, CaptionButton.Minimize, miniState)
            End If
            If Me.MinimizeBox Then
                ControlPaint.DrawCaptionButton(e.Graphics, closeBoxRect, CaptionButton.Close, closeState)
            End If
    
            e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic
            e.Graphics.PixelOffsetMode = PixelOffsetMode.Half
            e.Graphics.SmoothingMode = SmoothingMode.None
            e.Graphics.CompositingQuality = CompositingQuality.GammaCorrected
            e.Graphics.CompositingMode = CompositingMode.SourceCopy
    
            Using Brush1 As New SolidBrush(Color.PapayaWhip)
                Using Pen1 As New Pen(Brush1, 6)
                    e.Graphics.DrawEllipse(Pen1, MidPointXLeft - CInt(Me.Width / 2) + 2, MidPointYTop - CInt(Me.Height / 2) + 2, CInt(Me.Width) - 4, CInt(Me.Height) - 4)
                End Using
            End Using
    
            ' The below code was going to be used to draw a curved string in the "border" around the Form.
    
            'Dim text As String = "Form1"
    
            'Dim Test() As PointF = {New PointF(0, 0), New PointF(160, 0), New PointF(160, 200), New PointF(80, 150), New PointF(0, 200)}
    
            'Dim textPath As New GraphicsPath(Test, Int64)
    
            'Dim textBounds As RectangleF = textPath.GetBounds()
    
            'textPath.AddString(text, System.Drawing.FontFamily.GenericSansSerif, 1, 8, New Point(0, 0), System.Drawing.StringFormat.GenericDefault)
    
            'e.Graphics.DrawPath(Pens.Black, textPath)
    
        End Sub
    
        Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
            'Start to move the form.
            If (Me.ClientRectangle.Contains(e.Location)) Then
                x = e.X
                y = e.Y
            End If
    
            'Check and press the header buttons.
            Dim mousePos As Point = Me.PointToClient(Control.MousePosition)
            If (miniBoxRect.Contains(mousePos)) Then
                miniState = ButtonState.Pushed
            ElseIf (closeBoxRect.Contains(mousePos)) Then
                closeState = ButtonState.Pushed
            End If
        End Sub
    
        Private Sub CustomBorderColorForm_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseMove
            'Move and refresh.
            If (x <> 0 And y <> 0) Then
                Me.Location = New Point(Me.Left + e.X - x, Me.Top + e.Y - y)
                Me.Refresh()
            End If
        End Sub
    
        Private Sub CustomBorderColorForm_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
            'Reset the mouse point.
            x = 0
            y = 0
    
            'Check the button states and modify the window state.
            If miniState = ButtonState.Pushed Then
                Me.WindowState = FormWindowState.Minimized
                miniState = ButtonState.Normal
            ElseIf closeState = ButtonState.Pushed Then
                Me.Close()
            End If
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show("Cool")
        End Sub
    End Class


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.


    Monday, February 3, 2014 9:13 PM
  • You still haven't answered a very critical question.

    Is your form going to contain controls?


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    Yes it will contain controls.
    Tuesday, February 4, 2014 4:47 PM
  • You still haven't answered a very critical question.

    Is your form going to contain controls?


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    Yes it contains controls.
    Tuesday, February 4, 2014 4:58 PM
  • I saw the link that Mick D. provided, and for the round form it's really nice, but still have some problems with the code so I will upload it Here on SkyDrive .In this project there is the code with some changes I made, but still I have something I didn't know how to do.First the rectangle represented by rc is outside the circle, which shouldn't be.Next I need some help to make it elegant,like making gradient background(of the form).And one more thing, is that I need borders.Please help me out guys.  
    Tuesday, February 4, 2014 6:10 PM
  • The simple answer is that you need to work within the constraints of GDI+.

    When the transparency is simulated, the effect uses only a single color and is applied to whole pixels so there are limits to how "smooth" the effect will be.  To achieve the greatest possible result, you'll need to use finely-crafted source images that are designed to minimize the limitations.  Sticking to sharp lines and not allowing any blur on the pen is one tip.  Another common way to get around the issue is to include a black stroke around the outside edge of each shape; then a black transparency will typically smooth out nicely.

    If you need a more dazzling visual effect, move to a WPF or Silverlight project where the rendering is done with 3D acceleration instead of with old-fashioned GDI.

    Here's a simple example of what is about "as good as it gets" for GDI.  Note the different shapes in the image have varying degrees of "smoothness" depending on the angle and brush of the lines.

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            BackColor = Color.Black
            TransparencyKey = Color.Black
            Size = My.Resources.ExampleForm.Size
            BackgroundImage = My.Resources.ExampleForm
            FormBorderStyle = Windows.Forms.FormBorderStyle.None
        End Sub
    End Class


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    • Edited by Reed KimbleMVP Tuesday, February 4, 2014 6:27 PM typo
    • Proposed as answer by tommytwotrain Wednesday, February 5, 2014 12:19 AM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:12 PM
    Tuesday, February 4, 2014 6:26 PM
  • Unfortunately, since you are going to have controls, this has become a lot more complicated.

    Using a Layered Window will get you the drawing results that you are looking for, but Layered windows will only paint what you instruct them how to paint. They completely ignore the standard windows paint messages.

    Your options at this point are:

    1. As Reed Kimble suggests, migrate to WPF.

    2. Draw controls yourself instead of adding controls. Not much fun if you need textboxes or similar, but simple buttons and labels are no problem.

    3. Use the Layered Window as the background and then create a second form to contain the controls and move this with the Layered Window. (That's another question for you to raise should you choose this method).

    Here is the code for a layered window:

    Imports System.Runtime.InteropServices
    Imports System.Drawing.Imaging
    Imports System.Drawing.Drawing2D
    
    Partial Public Class Form1
    
        Public Sub New()
            InitializeComponent()
        End Sub
    
        Protected Overrides ReadOnly Property CreateParams() As CreateParams
            Get
                Dim cp As CreateParams = MyBase.CreateParams
                If Not Me.DesignMode Then
                    cp.ExStyle = cp.ExStyle Or NativeMethods.WS_EX_LAYERED
                End If
                Return cp
            End Get
        End Property
    
        Protected Overrides Sub OnResize(ByVal e As EventArgs)
            MyBase.OnResize(e)
            If Me.Created Then
                UpdateWindow()
            End If
        End Sub
    
        Protected Overrides Sub OnLocationChanged(ByVal e As EventArgs)
            MyBase.OnLocationChanged(e)
            If Me.Created Then
                UpdateWindow()
            End If
        End Sub
    
        Protected Overrides Sub OnVisibleChanged(ByVal e As EventArgs)
            MyBase.OnVisibleChanged(e)
            If Me.Visible Then
                UpdateWindow()
            End If
        End Sub
    
        Public Sub UpdateWindow()
    
            If Me.IsDisposed OrElse Me.Width <= 0 OrElse Me.Height <= 0 Then
                Return
            End If
    
            Dim borderWidth As Int32 = 24
    
            Using backBuffer As New Bitmap(Me.Width, Me.Height, PixelFormat.Format32bppPArgb)
    
                Using gr As Graphics = Graphics.FromImage(backBuffer)
    
                    gr.SmoothingMode = SmoothingMode.AntiAlias
                    gr.InterpolationMode = InterpolationMode.HighQualityBicubic
                    gr.PixelOffsetMode = PixelOffsetMode.HighQuality
                    gr.CompositingQuality = CompositingQuality.GammaCorrected
                    gr.CompositingMode = CompositingMode.SourceOver
    
                    Dim rc As Rectangle = Me.Bounds
                    rc.Offset(-Me.Left, -Me.Top)
                    rc.Inflate(-borderWidth / 2, -borderWidth / 2)
    
                    If rc.Width > 0 AndAlso rc.Height > 0 Then
    
                        Using linGrBrush As New LinearGradientBrush(rc, Color.Blue, Color.Red, LinearGradientMode.ForwardDiagonal)
                            gr.FillEllipse(linGrBrush, rc)
                        End Using
    
                        Using myPen As New Pen(Color.SteelBlue, borderWidth)
                            gr.DrawEllipse(myPen, rc)
                            myPen.Color = Color.LightSteelBlue
                            myPen.Width = 2
                            rc.Inflate(-borderWidth / 2, -borderWidth / 2)
                            gr.DrawEllipse(myPen, rc)
                        End Using
    
                    End If
    
                    'Use Interop to transfer the bitmap to the screen.
                    Dim screenDC As IntPtr = NativeMethods.GetDC(IntPtr.Zero)
                    Dim memDC As IntPtr = NativeMethods.CreateCompatibleDC(screenDC)
                    Dim hBitmap As IntPtr = backBuffer.GetHbitmap(Color.FromArgb(0))
                    Dim oldBitmap As IntPtr = NativeMethods.SelectObject(memDC, hBitmap)
    
                    Dim blend As New NativeMethods.BLENDFUNCTION(255)
                    Dim ptDst As Point = Me.Location
                    Dim szDst As Size = backBuffer.Size
                    Dim ptSrc As Point = Point.Empty
                    NativeMethods.UpdateLayeredWindow(Me.Handle, screenDC, ptDst, szDst, memDC, ptSrc, 0, blend, NativeMethods.ULW_ALPHA)
    
                    NativeMethods.SelectObject(memDC, oldBitmap)
                    NativeMethods.DeleteObject(hBitmap)
                    NativeMethods.DeleteDC(memDC)
                    NativeMethods.DeleteDC(screenDC)
    
                End Using
    
            End Using
    
        End Sub
    
    End Class
    
    Public Class NativeMethods
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Friend Shared Function UpdateLayeredWindow(ByVal hwnd As IntPtr, ByVal hdcDst As IntPtr, ByRef pptDst As Point, ByRef psize As Size, ByVal hdcSrc As IntPtr, ByRef pptSrc As Point, ByVal crKey As Int32, ByRef pblend As BLENDFUNCTION, ByVal dwFlags As Int32) As Boolean
        End Function
    
        <DllImport("user32.dll", SetLastError:=True)> _
        Friend Shared Function GetDC(ByVal hWnd As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function CreateCompatibleDC(ByVal dc As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function SelectObject(ByVal hdc As IntPtr, ByVal hObj As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function DeleteDC(ByVal dc As IntPtr) As IntPtr
        End Function
    
        <DllImport("gdi32.dll")> _
        Friend Shared Function DeleteObject(ByVal hObj As IntPtr) As IntPtr
        End Function
    
        <StructLayout(LayoutKind.Sequential, Pack:=1)> _
    Friend Structure BLENDFUNCTION
            Public BlendOp, BlendFlags, SourceConstantAlpha, AlphaFormat As Byte
            Public Sub New(ByVal alpha As Byte)
                Me.BlendOp = AC_SRC_OVER
                Me.BlendFlags = 0
                Me.SourceConstantAlpha = alpha
                Me.AlphaFormat = AC_SRC_ALPHA
            End Sub
        End Structure
    
        <StructLayout(LayoutKind.Sequential)> _
        Friend Structure RECT
            Public Left, Top, Right, Bottom As Int32
        End Structure
    
        Friend Const WS_EX_LAYERED As Int32 = &H80000
        Friend Const AC_SRC_OVER As Int32 = &H0
        Friend Const AC_SRC_ALPHA As Int32 = &H1
        Friend Const ULW_ALPHA As Int32 = &H2
    
    End Class

    and this is how it looks:


    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com


    • Edited by Mick Doherty Tuesday, February 4, 2014 7:44 PM
    • Proposed as answer by tommytwotrain Tuesday, February 4, 2014 11:13 PM
    • Marked as answer by Titanium man11 Thursday, February 6, 2014 5:13 PM
    Tuesday, February 4, 2014 7:40 PM
  • Very nice Mick! Here is how your code looks on my system for comparison to the other examples.


    • Edited by tommytwotrain Tuesday, February 4, 2014 11:15 PM changed pic
    Tuesday, February 4, 2014 11:13 PM
  • The simple answer is that you need to work within the constraints of GDI+.

    When the transparency is simulated, the effect uses only a single color and is applied to whole pixels so there are limits to how "smooth" the effect will be.  To achieve the greatest possible result, you'll need to use finely-crafted source images that are designed to minimize the limitations.  Sticking to sharp lines and not allowing any blur on the pen is one tip.  Another common way to get around the issue is to include a black stroke around the outside edge of each shape; then a black transparency will typically smooth out nicely.

    If you need a more dazzling visual effect, move to a WPF or Silverlight project where the rendering is done with 3D acceleration instead of with old-fashioned GDI.

    Here's a simple example of what is about "as good as it gets" for GDI.  Note the different shapes in the image have varying degrees of "smoothness" depending on the angle and brush of the lines.

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            BackColor = Color.Black
            TransparencyKey = Color.Black
            Size = My.Resources.ExampleForm.Size
            BackgroundImage = My.Resources.ExampleForm
            FormBorderStyle = Windows.Forms.FormBorderStyle.None
        End Sub
    End Class


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Reed,

    Another very nice approach. I guess with this one the difficulty is making the original bitmap with the smooth edge. However this one allows the controls so its going to the top for me on ease of use. Here is an example pic. Any roughness is in the original picture.

    Wednesday, February 5, 2014 12:19 AM
  • The simple answer is that you need to work within the constraints of GDI+.

    When the transparency is simulated, the effect uses only a single color and is applied to whole pixels so there are limits to how "smooth" the effect will be.  To achieve the greatest possible result, you'll need to use finely-crafted source images that are designed to minimize the limitations.  Sticking to sharp lines and not allowing any blur on the pen is one tip.  Another common way to get around the issue is to include a black stroke around the outside edge of each shape; then a black transparency will typically smooth out nicely.

    If you need a more dazzling visual effect, move to a WPF or Silverlight project where the rendering is done with 3D acceleration instead of with old-fashioned GDI.

    Here's a simple example of what is about "as good as it gets" for GDI.  Note the different shapes in the image have varying degrees of "smoothness" depending on the angle and brush of the lines.


    Reed,

    So how do you suggest making the background bitmap? I captured what I drew in my last example above with a black form background. I put it in your example but now I seem to have a little black fuzz on the edge. Is that due to the exact color of black in the bitmap? Also, when I copied your image in your post to ms paint the background was black, and it produces no black fuzz? Is it a transparent image or what am I missing? I figure Tman would ask if he was here.

     Here is my background bitmap and my running form screen shot.



    Wednesday, February 5, 2014 12:53 AM
  • Reed,

    You wrote: "Another common way to get around the issue is to include a black stroke around the outside edge of each shape; then a black transparency will typically smooth out nicely."

    What do you mean by a black stroke?

    Wednesday, February 5, 2014 12:58 AM
  • Reed or et al,

    You wrote "Sticking to sharp lines and not allowing any blur on the pen is one tip." 

    Again I don't know what this means. In my example is use:

         e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

    so is that blurring the pen? Can you tell us briefly what is happing with AntiAlias drawing mode? In a bitmap can one pixel have a blurr? Like two colors or is it just one dot and one color? Also will the bitmap format make any difference, ie .BMP vs .GIF?

    Thanks,

    Tom



    Wednesday, February 5, 2014 1:15 AM
  • I downloaded the project at this link from Code Project Custom AntiAliasing with GDI+ and after unzipping the project brought it up in Visual Studio where it upgraded fine then I ran it.

    It's in C# and was created to add greater anti-alias capability to GDI I think than GDI affords normally.

    So I am going to look through the code and see if I can use it to anti-alias to a greater capacity for drawing in the last code I posted. Don't know if it just works for images or drawing too. I'll do it sometime tomorrow.

    Below is an image with a magnified pic of the app running and below that a normal size pic of the app running. Used the "ease of access" magnifier to magnify it so it doesn't look that great.

    But images at the link look pretty nice. And below in the top pic see the left side of the cats tail going up. In the first two images left to right it's kind of squared off. In the right image it's mostly curved IMO.


    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.


    • Edited by Mr. Monkeyboy Wednesday, February 5, 2014 3:08 AM 5555
    Wednesday, February 5, 2014 3:06 AM
  • Drawing controls is by this way right:

     Dim btn As New Button
            btn.Location = New Point(20, 20)
            Me.Controls.Add(btn)

    cause it's not working

    Thursday, February 6, 2014 5:16 AM
  • Drawing controls is by this way right:

     Dim btn As New Button
            btn.Location = New Point(20, 20)
            Me.Controls.Add(btn)

    cause it's not working

    That's adding a control. Not drawing a control.

    I'm not sure if using a graphics path is considered drawing a control either. But this code uses a graphics path.

    Option Strict On
    
    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        Dim WithEvents Button1 As New Button
        Dim WithEvents Button2 As New Button
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.CenterToScreen()
    
            Button1.Name = "Button1"
            Button1.Size = New Size(125, 125)
            Button1.BackColor = Color.Yellow
            Button1.BackgroundImage = Image.FromFile("C:\Users\John\Desktop\Picture Files\Crossbones Bmp.Bmp")
            Button1.BackgroundImageLayout = ImageLayout.Zoom
    
            Me.Controls.Add(Button1)
    
            Dim BTN1 As New GraphicsPath()
            BTN1.AddEllipse(14, 4, 100, 100)
    
            Button1.Region = New Region(BTN1)
            Button1.Location = New Point(PictureBox1.Location.X + 100, PictureBox1.Location.Y + 100)
            Button1.BringToFront()
    
    
            Button2.Name = "Button2"
            Button2.Size = New Size(300, 300)
            Button2.BackColor = Color.LimeGreen
    
            Me.Controls.Add(Button2)
    
            Dim BTN2 As New GraphicsPath()
    
            Dim BTN2Array As Point() = {New Point(23, 20), New Point(40, 10), New Point(57, 20), New Point(50, 40), New Point(30, 40)}
    
            BTN2.AddPolygon(BTN2Array)
    
            Button2.Region = New Region(BTN2)
            Button2.Location = New Point(PictureBox1.Location.X + 300, PictureBox1.Location.Y + 100)
            Button2.BringToFront()
        End Sub
    
        Private Sub Button1Click(sender As Object, e As EventArgs) Handles Button1.Click
            Me.Text = "I'm Mr. Monkeyboys moniker."
        End Sub
    
        Private Sub Button2Click(sender As Object, e As EventArgs) Handles Button2.Click
            Me.Text = "I'm a lime green pentagon."
        End Sub
    
    End Class
    



    Please BEWARE that I have NO EXPERIENCE and NO EXPERTISE and probably onset of DEMENTIA which may affect my answers! Also, I've been told by an expert, that when you post an image it clutters up the thread and mysteriously, over time, the link to the image will somehow become "unstable" or something to that effect. :) I can only surmise that is due to Global Warming of the threads.



    • Edited by Mr. Monkeyboy Thursday, February 6, 2014 6:06 AM 5555
    Thursday, February 6, 2014 5:55 AM
  • Cool Monkey.
    Thursday, February 6, 2014 1:32 PM
  • Thanks for your efforts all.I decided to use WPF as Reed said.And I'll mark as answers what helped me,cause there was lots of things that helped me here.
    Thursday, February 6, 2014 4:32 PM