6
\$\begingroup\$

I've actually been struggling with painting with VB.Net for a few weeks. All I know is that I shouldn't use CreateGraphics if I can avoid it, so I've done just that. One of the questions comes from a CodeGolf challenge that requires users to draw sprockets.

This is only my beginning of that. I've never displayed anything I haven't drawn in excel. At first I tried a Class of sprockets, but it wouldn't fill my List properly, so I've boiled it down to

  1. populating an array
  2. passing that array to the form
  3. Painting my circles.

Essentially I read the input, convert it to integer array, send that to the form and draw the circles. I've probably made it way too complicated, but like I said, I've struggled for a few weeks, which is why I'm here. Parsing the input was pretty tricky to me, actually.

Input

Comes in the form of (sets of) 3 integers (x-position, y-position, radius) e.g.

(0, 0, 16), (100, 0, 16), (100, 100, 12), (50, 50, 24), (0, 100, 12)

Output

enter image description here

Standard Module

Option Explicit On
Option Strict On
Option Infer On
Option Compare Text
Imports System.IO
Module Module1
 Const INPUT_PATH As String = "C:\Temp\gearinput.txt"
 Public delimiter() As String = {"),"}
 Sub Main()
 Dim inputData() As String
 inputData = GetInput()
 Dim sprocketData() As String = Custom_Split(inputData(0))
 Dim paintingdata(,) As Integer = StringToIntArray(sprocketData)
 Dim targetForm As New Form1
 targetForm.Visible = True
 targetForm.DrawSprockets(targetForm, paintingdata)
 End Sub
 Private Function Custom_Split(ByVal stringToSplit As String) As String()
 stringToSplit = stringToSplit.Replace("(", String.Empty)
 stringToSplit = stringToSplit.Replace(" ", String.Empty)
 Dim stringArray() As String = stringToSplit.Split(delimiter, StringSplitOptions.RemoveEmptyEntries)
 stringArray(stringArray.Length - 1) = stringArray(stringArray.Length - 1).Replace(")", String.Empty)
 Return stringArray
 End Function
 Private Function StringToIntArray(ByVal sprocketdata() As String) As Integer(,)
 Dim firstDimensionSize As Integer = sprocketdata.GetUpperBound(0)
 Dim integerArray(firstDimensionSize, 2) As Integer
 Dim tempString() As String
 For i As Integer = 0 To firstDimensionSize
 tempString = sprocketdata(i).Split(","c)
 For j = 0 To 2
 integerArray(i, j) = Convert.ToInt32(tempString(j))
 Next
 Next
 Return integerArray
 End Function
 Private Function GetInput() As String()
 Return File.ReadAllLines(INPUT_PATH)
 End Function
End Module

Form Code

Imports System.Drawing
Imports System.Windows.Forms
Public Class Form1
 Const BUFFER As Integer = 20
 Dim xValue As Integer
 Dim yValue As Integer
 Dim pRadius As Integer
 Dim paintData(,) As Integer
 Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
 End Sub
Public Shared Sub DrawSprockets(ByVal myForm As Form1, ByVal dataArray(,) As Integer)
 myForm.paintData = dataArray
 For i As Integer = 0 To myForm.paintData.GetUpperBound(0)
 myForm.paintData(i, 0) += 10
 myForm.paintData(i, 1) += 10
 Next
 myForm.Refresh()
 End Sub
 Private Sub Form1_Paint(ByVal sender As Object, e As PaintEventArgs) Handles MyBase.Paint
Dim myPen As Pen
 myPen = New Pen(Brushes.Black)
 For i As Integer = 0 To paintData.GetUpperBound(0)
 e.Graphics.DrawEllipse(myPen, New Rectangle(paintData(i, 0), paintData(i, 1), paintData(i, 2), paintData(i, 2)))
 e.Graphics.FillEllipse(Brushes.Black, New Rectangle(paintData(i, 0), paintData(i, 1), paintData(i, 2), paintData(i, 2)))
 Next
 End Sub
End Class
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Mar 24, 2018 at 0:13
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

The overall structure of your code looks good, but the readability is a tad poor. You should always strive to follow the Framework Design Guidelines. Use proper naming and add a few linebreaks.

Rather than using arrays, create a dedicated "Sprocket" class to hold the parsed input data.

Public Class Sprocket
 Public Property X As Integer
 Public Property Y As Integer
 Public Property R As Integer
End Class

Now, if you add the rest of the non-numeric characters to the separator list you could actually read and parse the file in two lines. (Though you ougth to use the line-continuation character for readability as seen at the bottom)

Dim numbers = File.ReadAllText("C:\Temp\gearinput.txt").Split($"{Environment.NewLine} ,)(".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Select(Function(n) Integer.Parse(n)).ToArray()
Dim sprockets = Enumerable.Range(0, (numbers.Length \ 3)).Select(Function(i) New Sprocket With {.X = numbers(((i * 3) + 0)), .Y = numbers(((i * 3) + 1)), .R = numbers(((i * 3) + 2))}).ToArray()

Window

Sprocket.vb

Public Class Sprocket
 Public Property X As Integer
 Public Property Y As Integer
 Public Property R As Integer
 Public Overrides Function ToString() As String
 Return $"{{ X={Me.X}, Y={Me.Y}, R={Me.R} }}"
 End Function
End Class

Program.vb

Public Module Program
 <STAThread>
 Public Sub Main()
 'TODO: Read file
 Dim input = "(0, 0, 16), (100, 0, 16), (100, 100, 12), (50, 50, 24), (0, 100, 12)"
 Dim numbers = input _
 .Split($"{Environment.NewLine} ,)(".ToCharArray(), StringSplitOptions.RemoveEmptyEntries) _
 .Select(Function(n) Integer.Parse(n)) _
 .ToArray()
 Dim sprockets = Enumerable _
 .Range(0, (numbers.Length \ 3)) _
 .Select(Function(i) New Sprocket With
 {
 .X = numbers(((i * 3) + 0)),
 .Y = numbers(((i * 3) + 1)),
 .R = numbers(((i * 3) + 2))
 }) _
 .ToArray()
 Application.EnableVisualStyles()
 Application.SetCompatibleTextRenderingDefault(False)
 Application.Run(New Window(sprockets))
 End Sub
End Module

Window.vb

Public Class Window
 Inherits Form
 Private ReadOnly sprockets As Sprocket()
 Public Sub New(sprockets As Sprocket())
 If (sprockets Is Nothing) Then
 Throw New ArgumentNullException(NameOf(sprockets))
 End If
 Me.sprockets = sprockets
 Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
 Me.Text = "Sprockets"
 Me.AutoScaleMode = AutoScaleMode.Font
 Me.ClientSize = New Size(800, 450)
 End Sub
 Protected Overrides Sub OnPaint(e As PaintEventArgs)
 e.Graphics.Clear(Me.BackColor)
 e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
 For Each sprocket In Me.sprockets
 Dim diameter = (sprocket.R * 2)
 Dim rect = New Rectangle(sprocket.X, sprocket.Y, diameter, diameter)
 e.Graphics.FillEllipse(Brushes.Black, rect)
 Next
 End Sub
End Class
answered Mar 27, 2018 at 16:19
\$\endgroup\$
6
  • \$\begingroup\$ Thanks. Haven't had a chance to read this, but I didn't want you to think I wasn't interested! \$\endgroup\$ Commented Mar 28, 2018 at 21:26
  • 1
    \$\begingroup\$ @Raystafarian No problem. As a side note: Your entry point (sub Main) looks a bit weird. No reference to Application.Run (the start of the message pump). Visual Studio auto-generate the entry point for VB.NET applications. But to manually wire up the start (as I did in the Program module) you do as follows: Double click "My project" in the solution pane. Click "Application" tab and uncheck "Enable application framework". Then choose "Sub Main" from the "Startup object" dropdown. \$\endgroup\$ Commented Mar 29, 2018 at 9:32
  • \$\begingroup\$ Great, that's something I had no idea about - thanks \$\endgroup\$ Commented Mar 30, 2018 at 8:47
  • \$\begingroup\$ With naming, the guide is basically saying everything should be PascalCase except parameters in functions, I'm reading that correctly? \$\endgroup\$ Commented Mar 30, 2018 at 23:04
  • \$\begingroup\$ Yup. And even though the guide do not specify a convention for variables, the consensus is to use camelCase. \$\endgroup\$ Commented Mar 31, 2018 at 7:01

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.