Friday, April 21, 2006

VB: Annoying Joke Form

I came across a post in one of the beginners programming forums I read.  The programmer wanted to make a simple form, and when the user closed the form, it would continually pop-up additional forms with cute little messages of endearment (a-la the little programs that people would write and post on BBS’s back in the day when VB was first becoming popular. Other variations are the form that keeps moving when you click on the close button.) Although the purpose of the program in question is tasteless, I responded and helped the programmer with his task.

I am not sure which version of VB he was using, since this below code wouldn’t work in either VS.Net or Vb.Net 2003, but it is the code originally posted:

Public Class Form1
Dim joke As JokeForm
Dim intnewx As Integer = joke.Location.X
Dim intnewy As Integer = joke.Location.Y

Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

joke = New JokeForm
joke.Show()

Randomize()
intnewx = (Rnd()) * 400
intnewy = (Rnd()) * 400

End Sub
End Class

There were a number of things I found that didn’t work. The assignment of joke.Location.X and Y in the declarations to intnewx and intnewy are incorrect for a number of reasons. The form joke is not even instantiated at this point, so the results would be undefined. From reviewing the code later, it looks like the programmer was trying to use intnewx and intnewy as pointers to the values of X and Y, however they are declared as integers, so the assignment of a value to them will not change the values. And the use of Location.X and Location.Y is not appropriate; it is easier to use form.left and form.top. The user wanted a loop, however it was not included, and once the joke form is created and shown, it would immediately be destroyed since the program is in the process of exiting at this point. If there was a loop, randomize would need to be called outside of it as well.

The final code ended up looking like this:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Randomize()
    End Sub

    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        Dim joke As JokeForm
      
While (True)
            joke = New JokeForm

            joke.Show()

            joke.Left = CInt(Int((Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width * Rnd()) + 1))
            joke.Top = CInt(Int((Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height * Rnd()) + 1))

            joke = Nothing
        End While
    End Sub

A few things I did differently from the programmer. First, I called Randomize in the Form.Load method, which is better than calling Randomize each time you loop. I included an infinite loop (yuck) to keep the instantiated forms from being destroyed immediately. I also assigned the values to Left and Top after showing the form. I found that Visual Basic would override the position values if the values were assigned before show method is called. I converted the return from Rnd() to an integer since Rnd() will return a number between 0 and 1. I also used Windows.Forms.Screen.PrimaryScreen.WorkingArea.width and height as the lowerbound and upperbound values for the Rnd function, which will keep the new forms within the screen.

I can’t help but feel a little guilty for helping this guy out, but at the same time I am hoping he learned a little about VB programming from the experience. There are a number of interesting VB topics, such as how to instantiate forms, assigning values to position for forms, using the Randomize() and Rnd() functions, and although not advisable, how to put a program into an infinite loop. Although a bit juvenile, I seem to recall a little fake DOS prompt I once wrote in Pascal to make an individual think they typed “format c:”, so maybe juvenile behavior is a trend among young programmers.

No comments: