0

I'm trying to make a hangman application, but for whatever reason I can not get the word you must "guess" to show up properly. As you can see in the loop, a new label is created at every iteration. The label's text property is set as a character of wordString, defined as wordLetter. Once all properties of the new label are set, it is added to the form, points are defined to draw a line underneath the label, and xAxis (used for placing the next label to the right of the previous) and i are iterated. The problem is, only the first label shows up, or "P" from the wordString "PROGRAM". I believe it's because every time I iterate the loop, a new label of the same name "wordLabel" is created, preventing new labels from being created. I'm not sure how to get around this; even if I used an array, I'd still have to make a new label at every iteration.

The result

Dim point1, point2 As Point

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Dim i As Integer

    Dim wordString As String = "PROGRAM"
    Dim wordLetter As String
    Dim xAxis As Integer

    Do While i < wordString.Length
        Dim wordLabel As New Label

        wordLetter = wordString.Chars(i)

        wordLabel.Font = New Font("Comic Sans MS", 25)
        wordLabel.AutoSize = True
        wordLabel.Text = wordLetter
        wordLabel.BackColor = Color.Transparent
        wordLabel.Location = New System.Drawing.Point(xAxis + 7, 190)

        Me.Controls.Add(wordLabel)

        point1.X = Convert.ToInt32(wordLabel.Location.X) - 10
        point1.Y = Convert.ToInt32(wordLabel.Location.Y) + 40

        point2.X = Convert.ToInt32(wordLabel.Size.Width) - 13
        point2.Y = Convert.ToInt32(wordLabel.Location.Y) + 40

        xAxis += 3
        i += 1

    Loop
End Sub

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint

    e.Graphics.DrawLine(Pens.Black, point1, point2)

End Sub
  • `wordLabel` is your variable name, not the control name. Duplicating that won't cause the problem you are seeing, but you *are* losing the reference to the control, which will probably cause you problems later. I think your problem may be that you are only putting 3 pixels of space between each label. They are probably drawing on top of each other. – Bradley Uffner Feb 01 '17 at 15:32
  • Is there a reason for you to use multiple labels instead of appending the letters to one label? – 41686d6564 stands w. Palestine Feb 01 '17 at 15:32
  • @AhmedAbdelhameed My guess is that it will allow him to better position on the underlines for each letter, being that Comic Sans is not mono-spaced. – Bradley Uffner Feb 01 '17 at 15:33

1 Answers1

1

This should work for you. It keeps the last left position of the previous label.

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Try
        BuildHangman("PROGRAM")
    Catch ex As Exception
        MessageBox.Show(String.Concat("An error occurred: ", ex.Message))
    End Try
End Sub

Private Sub BuildHangman(wordString As String)

    Dim i As Integer
    Dim wordLetter As String
    Dim lastLeft As Integer

    Dim sensibleFont As New Font("Segoe UI", 25)

    Do While i < wordString.Length

        Dim wordLabel As New Label

        wordLetter = wordString.Chars(i)
        wordLabel.Font = sensibleFont
        wordLabel.AutoSize = True
        wordLabel.Text = wordLetter
        wordLabel.BackColor = Color.Transparent
        wordLabel.Location = New System.Drawing.Point(lastLeft + 7, 190)

        Me.Controls.Add(wordLabel)

        lastLeft = wordLabel.Left + wordLabel.Width

        i += 1

    Loop

End Sub
Andrew Mortimer
  • 2,380
  • 7
  • 31
  • 33
  • 1
    Keep in mind that creating a new `Font` every iteration should be avoided. Create it once, and reuse it. I'm not 100% positive right now, but I *think* font is `IDisposable`. – Bradley Uffner Feb 01 '17 at 15:34
  • Noted! What is the downside to creating a new font each time? I am wholly unaware. – Andrew Mortimer Feb 01 '17 at 15:41
  • Fonts contain unmanaged resources, specifically, a GDI Font Handle. The OS can only track a limited number of handles to GDI objects before it gives up and crashes your application. You have to be very careful with any drawing object you create (`Pen`, `Brush`, `Font`, `Bitmap`, etc...) that you create the minimum number needed and properly dispose of them. If you don't, you can have serious performance issues, or "random" crashing as the OS runs out of handles. – Bradley Uffner Feb 01 '17 at 15:47
  • It probably isn't a serious problem with this specific code, because the number of objects is limited by the max word length, but properly managing and cleaning up GDI objects is a *very* good habit to get in to early. – Bradley Uffner Feb 01 '17 at 15:51
  • Thanks. Useful info. I'll update the answer accordingly. – Andrew Mortimer Feb 01 '17 at 15:58
  • Well, this seems to work! I didn't even think of using the Control.Left property. It seems only the last point1 and point2 values are drawn; is there a way to run Form1_Paint at every loop iteration so a new line is drawn under every letter? I'm not really sure why I can't use e.Graphics outside of a Paint event, it's simply not allowed. –  Feb 02 '17 at 13:05
  • Have a look through this one : http://stackoverflow.com/questions/17895619/how-to-draw-a-line-in-vb-net – Andrew Mortimer Feb 02 '17 at 13:27