|
|
Title | Make a bouncing ball screen saver with VB .NET |
Description | |
Keywords | VB.NET, screen saver, commandline, command line, parameters |
Categories | Windows, Multimedia, Graphics |
|
|
The program starts from a Main subroutine. That routine examines the command line parameters for the flags /p, /c, and /s.
- /p
- The screen saver should display as a preview. The second command line argument gives the hWnd (window handle) of the preview window in which the program should draw the preview.
- /c
- The screen saver should display a configuration screen. This program displays the frmConfig form as a modal dialog and then exits.
- /s
- The screen saver should run as a normal screen saver. The program also runs in this mode if it receives no command line flag or some other flag. To display as a normal screen saver, the program displays the frmCanvas form as a modal dialog.
|
|
Private Enum ActionType
actConfigure
actPreview
actRun
End Enum
Public m_Action As ActionType
Public Sub Main(ByVal args As String())
' See what we should do.
If args.Length = 0 Then
m_Action = ActionType.actRun
Else
Select Case args(0).ToLower().Substring(0, 2)
Case "/p"
m_Action = ActionType.actPreview
Case "/c"
m_Action = ActionType.actConfigure
Case "/s"
m_Action = ActionType.actRun
Case Else
m_Action = ActionType.actRun
End Select
End If
' Do it.
Select Case m_Action
Case ActionType.actRun
' Normal screen saver.
Dim canvas As New frmCanvas
Application.Run(canvas)
Case ActionType.actConfigure
' Configure.
Dim dlg_config As New frmConfig
Application.Run(dlg_config)
Case ActionType.actPreview
' Preview.
Dim canvas As New frmCanvas
SetForm(canvas, args(1))
Application.Run(canvas)
End Select
End Sub
|
|
The frmConfig form loads the number of balls from the registry using GetSetting. If the user changes the value and clicks OK, the program saves the new value using SaveSetting.
|
|
' Display the current settings.
Private Sub Config_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
txtNumBalls.Text = GetSetting("Bouncer", "Settings", _
"NumBalls", "20")
End Sub
' Save the new settings.
Private Sub cmdOk_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdOk.Click
Try
SaveSetting("Bouncer", "Settings", "NumBalls", _
CLng(txtNumBalls.Text))
Catch exc As Exception
End Try
Close()
End Sub
|
|
If the program is running as a preview, it calls subroutine SetForm to reparent the frmCanvas form into the preview window.
|
|
' Reparent the form into the preview window.
Private Sub SetForm(ByRef frm As Form, ByRef arg As String)
Dim style As Integer
Dim preview_hwnd As Integer = Integer.Parse(CType(arg, _
String))
Dim r As New RECT
' Get the preview window's size.
GetClientRect(preview_hwnd, r)
With frm
.WindowState = FormWindowState.Normal
.FormBorderStyle = FormBorderStyle.None
.Width = r.right
.Height = r.bottom
End With
' Add the WS_CHILD style to the form.
style = GetWindowLong(frm.Handle.ToInt32, GWL_STYLE)
style = style Or WS_CHILD
SetWindowLong(frm.Handle.ToInt32, GWL_STYLE, style)
' Reparent the form into the preview window.
SetParent(frm.Handle.ToInt32, preview_hwnd)
' Set the form's GWL_PARENT value to the preview window.
SetWindowLong(frm.Handle.ToInt32, GWL_HWNDPARENT, _
preview_hwnd)
' Position the form in the preview window.
SetWindowPos(frm.Handle.ToInt32, 0, r.left, 0, r.right, _
r.bottom, _
SWP_NOACTIVATE Or SWP_NOZORDER Or SWP_SHOWWINDOW)
End Sub
|
|
The frmCanvas form displays the normal screen saver. At design time, the form gets these property values:
Property | Value |
BackColor | System.Drawing.Color.Black |
ControlBox | False |
FormBorderStyle | System.Windows.Forms.FormBorderStyle.None |
MaximizeBox | False |
MinimizeBox | False |
ShowInTaskbar | False |
WindowState | System.Windows.Forms.FormWindowState.Maximized |
When the form loads, it determines whether it is running as a preview or a screen saver. If it is running as a screen saver, it hides the cursor. If it is running as a preview, it removes the KeyDown, MouseMove, and MouseDown event handlers so the user doens't stop the preview.
The program then reads the number of balls it should animate using GetSetting. It generates values (radius, location, speed, and color) to define that many random balls. It also creates a memory bitmap to represent the form and makes a Graphics object attached to it.
When the form's Timer event handler fires, the program clears the memory bitmap. Then for each ball, it adds the X and Y components of the ball's velocity to the ball's position, bouncing back any ball that hits an edge of the screen. The event handler then draws the ball on the memory bitmap.
After it has drawn all of the balls in memory, the program copies the memory bitmap onto the screen.
If the user moves the mouse, clicks a mouse button, or presses a key, the form closes itself to end the program.
|
|
Private m_Xmax As Integer
Private m_Ymax As Integer
' (X, Y) is the ball's upper left corner.
' D is the ball's diameter.
Private m_NumBalls As Long
Private m_Color() As Color
Private m_D() As Single
Private m_X() As Single
Private m_Y() As Single
Private m_Vx() As Single
Private m_Vy() As Single
Private m_BufferBitmap As Bitmap
Private m_BufferGraphics As Graphics
Private m_Graphics As Graphics
Private m_Random As New Random
' Hide the cursor, get ready, and enable
' the timer.
Private Sub frmCanvas_Load(ByVal sender As Object, ByVal e _
As System.EventArgs) Handles MyBase.Load
' See if we are running as a preview or screen saver.
If m_Action = ActionType.actRun Then
' Screen saver. Hide the cursor.
Cursor.Hide()
Else
' Preview. Remove the KeyDown, MouseMove, and
' MouseDown event handlers.
RemoveHandler Me.KeyDown, AddressOf _
frmCanvas_KeyDown
RemoveHandler Me.MouseMove, AddressOf _
frmCanvas_MouseMove
RemoveHandler Me.MouseDown, AddressOf _
frmCanvas_MouseDown
End If
' Save the screen width and height.
m_Xmax = Width
m_Ymax = Height
' Get the number of balls.
m_NumBalls = CLng(GetSetting("Bouncer", "Settings", _
"NumBalls", "20"))
' Create the balls.
ReDim m_Color(m_NumBalls)
ReDim m_D(m_NumBalls)
ReDim m_X(m_NumBalls)
ReDim m_Y(m_NumBalls)
ReDim m_Vx(m_NumBalls)
ReDim m_Vy(m_NumBalls)
Const MAX_VEL As Single = 0.025
Const MIN_D_FACTOR As Single = 0.025
Const MAX_D_FACTOR As Single = 0.1
For i As Integer = 0 To m_NumBalls - 1
m_Color(i) = Color.FromArgb(&HFF000000 Or _
QBColor(m_Random.Next(1, 15)))
m_D(i) = RandomSingle(m_Ymax * MIN_D_FACTOR, m_Ymax _
* MAX_D_FACTOR)
m_X(i) = RandomSingle(1, m_Xmax - m_D(i))
m_Y(i) = RandomSingle(1, m_Ymax - m_D(i))
m_Vx(i) = RandomSingle(-m_Ymax * MAX_VEL, m_Ymax * _
MAX_VEL)
m_Vy(i) = RandomSingle(-m_Ymax * MAX_VEL, m_Ymax * _
MAX_VEL)
Next i
' Make a buffer Bitmap and Graphics.
m_BufferBitmap = New Bitmap(m_Xmax, m_Ymax)
m_BufferGraphics = Graphics.FromImage(m_BufferBitmap)
' Create a Graphics object for the form.
m_Graphics = CreateGraphics()
' Enable the timer.
tmrMove.Enabled = True
End Sub
' Return a random Single between min_value and max_value.
Private Function RandomSingle(ByVal min_value As Single, _
ByVal max_value As Single) As Single
Return min_value + (max_value - min_value) * _
m_Random.NextDouble()
End Function
' Move the balls.
Private Sub tmrMove_Tick(ByVal sender As Object, ByVal e As _
System.EventArgs) Handles tmrMove.Tick
Dim i As Long
' Draw on the memory bitmap.
m_BufferGraphics.Clear(System.Drawing.Color.Black)
For i = 0 To m_NumBalls - 1
' Update the ball's X coordinate.
m_X(i) += m_Vx(i)
If m_X(i) < 1 Then
m_X(i) = 1 - m_X(i)
m_Vx(i) *= -1
ElseIf m_X(i) > m_Xmax - m_D(i) Then
m_X(i) = (m_Xmax - m_D(i)) - (m_X(i) - (m_Xmax _
- m_D(i)))
m_Vx(i) *= -1
End If
' Update the ball's Y coordinate.
m_Y(i) += m_Vy(i)
If m_Y(i) < 1 Then
m_Y(i) = 1 - m_Y(i)
m_Vy(i) *= -1
ElseIf m_Y(i) > m_Ymax - m_D(i) Then
m_Y(i) = (m_Ymax - m_D(i)) - (m_Y(i) - (m_Ymax _
- m_D(i)))
m_Vy(i) *= -1
End If
' Draw the ball.
Dim the_brush As New SolidBrush(m_Color(i))
m_BufferGraphics.FillEllipse(the_brush, _
m_X(i), m_Y(i), m_D(i), m_D(i))
Dim the_pen As New Pen(m_Color(i))
m_BufferGraphics.DrawEllipse(the_pen, _
m_X(i), m_Y(i), m_D(i), m_D(i))
the_brush.Dispose()
the_pen.Dispose()
Next i
' Copy the image onto the screen.
m_Graphics.DrawImage(m_BufferBitmap, 0, 0)
End Sub
' Stop if the mouse moves.
Private Sub frmCanvas_MouseMove(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles _
MyBase.MouseMove
Static done_before As Boolean
Static mouse_x As Long
Static mouse_y As Long
' If this is the first time,
' save the mouse position.
If Not done_before Then
done_before = True
mouse_x = e.X
mouse_y = e.Y
Else
' See if the mouse has moved.
If Math.Abs(e.X - mouse_x) > 10 Or _
Math.Abs(e.Y - mouse_y) > 10 _
Then
' Close the form.
Me.Close()
End If
End If
End Sub
' Stop if the mouse button is pressed.
Private Sub frmCanvas_MouseDown(ByVal sender As Object, _
ByVal e As System.Windows.Forms.MouseEventArgs) Handles _
MyBase.MouseDown
Me.Close()
End Sub
' Stop if the user presses a key.
Private Sub frmCanvas_KeyDown(ByVal sender As Object, ByVal _
e As System.Windows.Forms.KeyEventArgs) Handles _
MyBase.KeyDown
Me.Close()
End Sub
|
|
Tip
In a program such as this one that reads command line parameters, it is handy to test the program with different parameters. In this example, you can test the program with the /c parameter.
It's a real hassle, however, to have to compile the program and then launch it from a shortcut or DOS window so you can pass it different parameters. Fortunately you can make the development environment start the program with command line parameters.
In Project Explorer, select the project. Then select the View menu's Property Pages command.
Click the Configuration Properties category and select Debugging. Enter the parameters you want to use in the "Command line arguments" text box.
Note
To install the screen saver, compile the program into an executable file. Change the file's extension from .exe to .scr and copy it into the system directory. That's all you need to do.
|
|
|
|
|
|