Search code examples
.netvb.netgraphics2dsystem.drawing

Drawing a Circle in VB.NET with given Size and X/Y POS producing unexpected results


I'm making an application that draws a circle when given the inputs of the Diameter and the Center Point of the Circle's X and Y via. a TextBox inside a PictureBox.

When I run the application and put in a constant X and Y but slowly increase/decrease the diameter of the circle, the circle starts randomly moving in position even though the X and Y positions are constant. Sometimes, if I refresh the PictureBox when any of the variables were not changed (X Pos, Y Pos, and Diameter), the circles moves for no reason at all even though nothing was changed...

This is code to reproduce:

These variables were already declared:

    Dim beginSCircleXPos As Integer 'What the user put into as the circle's center for X
    Dim beginSCircleYPos As Integer 'What the user put into as the circle's center for y

    Dim sCircleXPos As Integer 'Top-Left point of the circle in X
    Dim sCircleYPos As Integer 'Top-Left point of the circle in Y
    Dim sCircleDiameter As Integer 'The diameter that user put into.


    Dim sCenterPointX As Integer 'Variables will be updated later
    Dim sCenterPointY As String

PictureBox's Paint event

beginSCircleXPos = TextBox1.Text
        beginSCircleYPos = TextBox2.Text

        sCircleXPos = beginSCircleXPos - sCircleDiameter / 2
        sCircleYPos = beginSCircleYPos - sCircleDiameter / 2


        sCircleDiameter = TextBox3.Text


        Using path As New GraphicsPath
            path.AddEllipse(sCircleXPos, sCircleYPos, sCircleDiameter, sCircleDiameter)
            sCenterPointX = sCircleXPos + sCircleDiameter / 2
            sCenterPointY = sCircleYPos + sCircleDiameter / 2

            Using brush As New PathGradientBrush(path)
                brush.CenterPoint = New PointF(sCenterPointX, sCenterPointY) 
                brush.CenterColor = Color.FromArgb(0, Color.Orange)
                brush.SurroundColors = {Color.Orange}
                brush.FocusScales = PointF.Empty

                e.Graphics.FillRectangle(brush, sCircleXPos, sCircleYPos, sCircleDiameter, sCircleDiameter)
            End Using
        End Using

It is worth noting that the PictureBox is refreshed by clicking a button with the PictureBox1.Refresh() command.

How can I fix this so that the Input of the Center Point and the X/Y values will result in a correct and constant answer every time?

EDIT:

  beginSCircleXPos = Convert.ToSingle(TextBox1.Text)
        beginSCircleYPos = Convert.ToSingle(TextBox2.Text)


        sCircleXPos = beginSCircleXPos - sCircleDiameter / 2
        sCircleYPos = beginSCircleYPos - sCircleDiameter / 2


        sCircleDiameter = Convert.ToSingle(TextBox3.Text)






        Using path As New GraphicsPath
            path.AddEllipse(sCircleXPos, sCircleYPos, sCircleDiameter, sCircleDiameter)
            sCenterPointX = sCircleXPos + sCircleDiameter / 2
            sCenterPointY = sCircleYPos + sCircleDiameter / 2

            Using brush As New PathGradientBrush(path)
                brush.CenterPoint = New PointF(sCenterPointX, sCenterPointY) 
                brush.CenterColor = Color.FromArgb(0, Color.Orange)
                brush.SurroundColors = {Color.Orange}
                brush.FocusScales = PointF.Empty

                e.Graphics.FillRectangle(brush, sCircleXPos, sCircleYPos, sCircleDiameter, sCircleDiameter)
            End Using
        End Using
    ```
Variables:

Dim beginSCircleXPos As Single Dim beginSCircleYPos As Single

Dim sCircleXPos As Single
Dim sCircleYPos As Single
Dim sCircleDiameter As Single


Dim sCenterPointX As Single
Dim sCenterPointY As Single


Solution

  • I didn't look too closely at your code. I still had the code that I provided to answer your previous question so I used that as a basis and just modified it as I would do it myself. I used a Timer to repaint the PictureBox once every second to make it a bit simpler. This is what I ended up with:

    Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
        Dim centreX As Single
        Dim centreY As Single
        Dim diameter As Single
    
        If Single.TryParse(TextBox1.Text, centreX) AndAlso
           Single.TryParse(TextBox2.Text, centreY) AndAlso
           Single.TryParse(TextBox3.Text, diameter) Then
            Dim radius = diameter / 2.0F
            Dim bounds As New RectangleF(centreX - radius,
                                         centreY - radius,
                                         diameter,
                                         diameter)
    
            Using path As New GraphicsPath
                path.AddEllipse(bounds)
    
                Using brush As New PathGradientBrush(path) With {.CenterPoint = New PointF(centreX, centreY),
                                                                 .CenterColor = Color.FromArgb(0, Color.Orange),
                                                                 .SurroundColors = {Color.Orange},
                                                                 .FocusScales = PointF.Empty}
                    e.Graphics.FillRectangle(brush, bounds)
                End Using
            End Using
        End If
    End Sub
    
    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        PictureBox1.Invalidate()
    End Sub
    

    It seemed to work just as expected for me. If one or more of the TextBoxes didn't contain a valid number then nothing was drawn, otherwise a graded circle was drawn where and how expected. If I set the centre coordinates and then varied the diameter, the circle that was drawn maintained a constant centre but grew and shrunk as expected.

    You can obviously use a Button.Click instead of a Timer.Tick if you want.