The following two programming examples, Minesweeper and Calculator, utilize ActiveX controls and VBScript. These examples show how ActiveX controls, along with some VBScript code, can be used to create interesting interactive web pages. The complete code for these examples can be found at the end of this chapter and on the companion CD that comes with this book.
The Minesweeper example is a simple Internet version of the popular Microsoft Minesweeper game that shipped with Windows 3.1. Players are presented with a 5-by-5 grid of cells. Cells are "swept" when they are clicked. If the cell doesn't contain a mine, it is cleared along with all the adjacent cells that do not contain mines. Uncovering a mine ends the game. When the player believes that all the mines have been identified, he or she clicks on the Done Sweeping button to see whether he or she has won. Figure 4-16 shows a sample of the minesweeper interface. Listing 4-8, starting on page 104, shows the code for the Internet version of the Minesweeper game. Since some of the code for the Minesweeper example is repetitive, only the basic code structure is included in Listing 4-8. The full program listing is available on the companion CD, in the samples folder.
Figure 4-16.
The Minesweeper interface.
The Minesweeper grid of cells is an HTML table defined by the <TABLE></TABLE> tags. A label control is placed inside each cell with the <OBJECT></OBJECT> tags. Note that this control is not the same as the Label control found in Visual Basic 4.0 and does not support control arrays, which are discussed in more detail later in this section. Therefore, all of the code was created with discrete instances of the Label control. The following code shows the definition of the Label control:
<OBJECT
CLASSID="clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell5" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
The controls are all built into a form called frmSweeper, using the <FORM></FORM> tags. The intrinsic Button controls are added to the form with the <INPUT> tag, as shown here:
<INPUT TYPE="BUTTON" ID="cmdShow" VALUE="Show All Mines" WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdNew" VALUE="New Game" WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdDone" VALUE="Done Sweeping" WIDTH=30>
These controls will automatically call the associated OnClick event subroutine as coded in VBScript.
As shown in the Minesweeper example, many controls in the Internet Explorer do not support control arrays. A control array is a group of the same controls, all of which have the same name. The controls are differentiated by the values of their index property. Every control in the array can call the same event-handling routine and pass its index value as an argument. Control arrays are great timesavers because when you use them you don't have to write an event-handling routine for each control.
The second example presented in this section is a simple four-function calculator. It uses the OnClick event of intrinsic Button controls to simulate control arrays. In the OnClick event, a separate routine is called, and an index is passed. Listing 4-9, starting on page 113, shows the complete project, but the following code shows the workaround for the control array:
<INPUT TYPE="BUTTON" NAME="btnOne" VALUE="1"
OnClick="Call NumPad(1)">
Note that the OnClick event can be used to execute code directly. This strategy is in contrast to that used in the Minesweeper example, in which the Click events were called because the controls were part of a form. Using the
OnClick event, as we did for the calculator, results in HTML code that is considerably shorter than the code for the Minesweeper game. Figure 4-17 shows a sample of the calculator interface.
Figure 4-17.
The four-function calculator interface.
The remaining portion of this chapter contains the program listings for the Minesweeper and Calculator examples.
<HTML>
<HEAD>
<TITLE>Minesweeper</TITLE>
<!--
This sample creates a Minesweeper game that uses
25 label controls in a table structure. Players
clear cells by clicking on them. If a cell doesn't
contain a mine, it's cleared along with all
adjacent cells that don't contain mines. If a cell
contains a mine and the player tries to clear it,
the game is over.
-->
<SCRIPT LANGUAGE="VBScript">
<!--
Sub lblCell1_Click
Call Sweep(1,Document.frmSweeper.lblCell1)
End Sub
Sub lblCell2_Click
Call Sweep(2,Document.frmSweeper.lblCell2)
End Sub
Sub lblCell3_Click
Call Sweep(3,Document.frmSweeper.lblCell3)
End Sub
Sub lblCell4_Click
Call Sweep(4,Document.frmSweeper.lblCell4)
End Sub
Sub lblCell5_Click
Call Sweep(5,Document.frmSweeper.lblCell5)
End Sub
.
.
.
Sub lblCell25_Click
Call Sweep(25,Document.frmSweeper.lblCell25)
End Sub
Sub Sweep(intIndex,lblCell)
'Author: New Technology Solutions, Inc.
'Purpose: This code handles the Click
'events for all the labels. When a
'label is clicked, we check to see if it
'contains a mine.
'5/1/96 Original
Dim i
Dim MyForm
Set MyForm=Document.frmSweeper
If Playing=0 Then Exit Sub
If Mine(intIndex)=0 Then
lblCell.Caption=""
Call ClearOthers(intIndex)
Else
lblCell.Caption="*"
Call YouLose()
End If
End Sub
'Author: New Technology Solutions, Inc.
'Purpose: The variables are dimensioned
'here. They are dimensioned inline so that
'they are available to all code in the page.
'They are declared when the page loads.
'5/9/96 Original
Dim Playing
Dim Mine(25)
Sub SetCellCaption(ByVal intMine,ByVal strCaption)
'Author: New Technology Solutions, Inc.
'Purpose: Set the caption of a label in the grid
'5/1/96 Original
Dim MyForm
Set MyForm=Document.frmSweeper
Select Case intMine
Case 1
MyForm.lblCell1.Caption=strCaption
Case 2
MyForm.lblCell2.Caption=strCaption
Case 3
MyForm.lblCell3.Caption=strCaption
Case 4
MyForm.lblCell4.Caption=strCaption
Case 5
MyForm.lblCell5.Caption=strCaption
.
.
.
Case 25
MyForm.lblCell25.Caption=strCaption
End Select
End Sub
Function GetCellCaption(ByVal intMine)
'Author: New Technology Solutions, Inc.
'Purpose: Return the current label caption
'5/1/96 Original
Dim MyForm
Set MyForm=Document.frmSweeper
If intMine=1 Then _
GetCellCaption=MyForm.lblCell1.Caption
If intMine=2 Then _
GetCellCaption=MyForm.lblCell2.Caption
If intMine=3 Then _
GetCellCaption=MyForm.lblCell3.Caption
If intMine=4 Then _
GetCellCaption=MyForm.lblCell4.Caption
If intMine=5 Then _
GetCellCaption=MyForm.lblCell5.Caption
.
.
.
If intMine=25 Then _
GetCellCaption=MyForm.lblCell25.Caption
End Function
-->
</SCRIPT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub ResetGame()
'Author: New Technology Solutions, Inc.
'Purpose: Reset the variables and the game board
'5/1/96 Original
Dim i
Dim n
For i=1 to 25
Mine(i)=0
Call SetCellCaption(i,"X")
Next
Randomize Timer
For i=1 to 5
n=Int(25*Rnd)+1
Mine(n)=1
Next
Playing=1
End Sub
Sub ClearOthers(ByVal intMine)
'Author: New Technology Solutions, Inc.
'Purpose: This routine clears adjacent
'cells that do not have a mine in them
'5/1/96 Original
Dim MyForm
Set MyForm=Document.frmSweeper
Select Case intMine
Case 1
If Mine(2)=0 Then MyForm.lblCell2.Caption=""
If Mine(6)=0 Then MyForm.lblCell6.Caption=""
If Mine(7)=0 Then MyForm.lblCell7.Caption=""
Case 2
If Mine(1)=0 Then MyForm.lblCell1.Caption=""
If Mine(3)=0 Then MyForm.lblCell3.Caption=""
If Mine(6)=0 Then MyForm.lblCell6.Caption=""
If Mine(7)=0 Then MyForm.lblCell7.Caption=""
If Mine(8)=0 Then MyForm.lblCell8.Caption=""
Case 3
If Mine(2)=0 Then MyForm.lblCell2.Caption=""
If Mine(4)=0 Then MyForm.lblCell4.Caption=""
If Mine(7)=0 Then MyForm.lblCell7.Caption=""
If Mine(8)=0 Then MyForm.lblCell8.Caption=""
If Mine(9)=0 Then MyForm.lblCell9.Caption=""
Case 4
If Mine(3)=0 Then MyForm.lblCell3.Caption=""
If Mine(5)=0 Then MyForm.lblCell5.Caption=""
If Mine(8)=0 Then MyForm.lblCell8.Caption=""
If Mine(9)=0 Then MyForm.lblCell9.Caption=""
If Mine(10)=0 Then MyForm.lblCell10.Caption=""
Case 5
If Mine(4)=0 Then MyForm.lblCell4.Caption=""
If Mine(9)=0 Then MyForm.lblCell9.Caption=""
If Mine(10)=0 Then MyForm.lblCell10.Caption=""
.
.
.
Case 25
If Mine(24)=0 Then MyForm.lblCell24.Caption=""
If Mine(19)=0 Then MyForm.lblCell19.Caption=""
If Mine(20)=0 Then MyForm.lblCell20.Caption=""
End Select
End Sub
Sub YouLose()
'Author: New Technology Solutions, Inc.
'Purpose: Display losing message
'5/1/96 Original
MsgBox "Oh, no! You Lose!",32,"Minesweeper"
Playing=0
End Sub
Sub YouWin()
'Author: New Technology Solutions, Inc.
'Purpose: Display winning message
'5/1/96 Original
MsgBox "Congratulations! You Win!",64,"Minesweeper"
Playing=0
End Sub
Sub cmdNew_OnClick()
'Author: New Technology Solutions, Inc.
'Purpose: Initialize game
'5/1/96 Original
Call ResetGame()
MsgBox "Ready to Play!",64,"Minesweeper"
End Sub
Sub cmdDone_OnClick()
'Author: New Technology Solutions, Inc.
'Purpose: This routine is called when the
'player thinks he or she has found all the mines
'5/1/96 Original
Dim blnWinLose
Dim i
blnWinLose=1
For i=1 to 25
If Mine(i)=0 And GetCellCaption(i)="X" Then
blnWinLose=0
End if
Next
If blnWinLose=1 Then
Call YouWin()
Else
Call YouLose()
End If
End Sub
Sub cmdShow_OnClick()
'Author: New Technology Solutions, Inc.
'Purpose: This routine shows all the
'mine locations for the current game
'5/1/96 Original
Dim i
For i=1 to 25
If Mine(i)=1 Then
Call SetCellCaption(i,"*")
Else
Call SetCellCaption(i,"")
End If
Next
Playing=0
End sub
-->
</SCRIPT>
</HEAD>
<BODY BGCOLOR="White">
<CENTER>
<H2>Minesweeper!</H2><BR>
<!--
This HTML code builds the form that
contains the label controls and
the buttons
-->
<FORM NAME="frmSweeper">
<FONT FACE="Arial" Size="12">
<TABLE BORDER CELLPADDING="5" WIDTH=100>
<TR ALIGN="MIDDLE" VALIGN="BASELINE">
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell1" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell2" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell3" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell4" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell5" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
</TR>
.
.
.
<TD ALIGN="CENTER" NOWRAP WIDTH=20>
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblCell25" HEIGHT=20 WIDTH=20>
<PARAM NAME="Caption" VALUE="X">
</OBJECT>
</TD>
</TR>
<CAPTION ALIGN="BOTTOM">Click on a cell</CAPTION>
</TABLE>
<INPUT TYPE="BUTTON" ID="cmdShow" VALUE="Show All Mines"
WIDTH=30>
<INPUT TYPE="BUTTON" ID="cmdNew" VALUE="New Game" WIDTH=30>
<INPUT TYPE="Button" ID="cmdDone" VALUE="Done Sweeping"
WIDTH=30>
<BR>
</FONT>
</FORM>
</CENTER>
<SCRIPT LANGUAGE="VBScript">
<!--
'This code is called inline after
'the rest of the page is set up.
'It initializes the game.
Call ResetGame()
-->
</SCRIPT>
</BODY>
</HTML>
Listing 4-9.
The four-function calculator example.
<HTML>
<HEAD>
<TITLE>Calculator</TITLE>
<!--
This demo implements a simple four-function
calculator
-->
<SCRIPT LANGUAGE="VBScript">
<!--
`Author: New Technology Solutions, Inc.
`Purpose:
`These are variables used throughout
`the calculator. They are declared
`inline as the page loads and are
`available to the entire application.
`5/1/96 Original
`Variable for user storage
Dim dblMemory
`Flag indicating whether decimal button
`has been clicked
Dim blnDecimal
`Display cache
Dim dblDisplay
`Temporary storage for chain calculations
Dim dblStorage
`Number of keystrokes entered
Dim intKeyStrokes
`Any pending mathematical operations
Dim intPending
`Initialize variables
dblMemory = 0
blnDecimal = 0
intKeyStrokes = 0
dblDisplay = 0
dblStorage = 0
intPending = 0
-->
</SCRIPT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub NumPad(intIndex)
`Author: New Technology Solutions, Inc.
`Purpose:
`Receive all button clicks for
`numbers on the calculator.
`The buttons do not support control
`arrays, but note how the OnClick
`attribute is used as a workaround to
`call the same routine for each button.
`5/1/96 Original
intKeyStrokes = intKeyStrokes + 1
If blnDecimal=0 Then
dblDisplay = dblDisplay * 10 + intIndex
Else
dblDisplay = dblDisplay + _
intIndex/(10 ^ intKeyStrokes)
End If
Call UpdateDisplay(dblDisplay)
End Sub
-->
</SCRIPT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub btnClear_OnClick
`Author: New Technology Solutions, Inc.
`Purpose: Clear the calculator display
`5/1/96 Original
intKeyStrokes = 0
dblDisplay = 0
blnDecimal = 0
dblStorage = 0
dblMemory = 0
Call UpdateDisplay(0)
End Sub
Sub btnDecimal_OnClick
`Author: New Technology Solutions, Inc.
`Purpose: Handle the Decimal button
`5/1/96 Original
intKeyStrokes = 0
blnDecimal = 1
End Sub
-->
</SCRIPT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub OperationPad(intIndex)
`Author: New Technology Solutions, Inc.
`Purpose: Handle addition, subtraction,
`multiplication, and division
`5/1/96 Original
Call DoPending()
`Reset all flags
intKeyStrokes = 0
blnDecimal = 0
intPending = intIndex
dblDisplay = 0
`Update calculator display
Call UpdateDisplay(dblStorage)
End Sub
Sub btnEquals_OnClick
`Author: New Technology Solutions, Inc.
`Purpose: Handle Equals key
`5/1/96 Original
intKeyStrokes = 0
blnDecimal = 0
Call DoPending()
dblDisplay = 0
Call UpdateDisplay(dblStorage)
dblStorage = 0
End Sub
Sub DoPending()
`Author: New Technology Solutions, Inc.
`Purpose:
`Handle any pending actions
`during chain calculations
`5/1/96 Original
`No pending operations
If intPending = 0 Then
dblStorage = dblDisplay
End If
`Chain addition
If intPending = 1 Then
dblStorage = dblStorage + dblDisplay
End If
`Chain subtraction
If intPending = 2 Then
dblStorage = dblStorage - dblDisplay
End if
`Chain multiplication
If intPending = 3 Then
dblStorage = dblStorage * dblDisplay
End if
`Chain division
If intPending = 4 Then
If dblStorage = 0 Then
intPending = 0
Exit Sub
End If
dblStorage = dblStorage / dblDisplay
End If
intPending = 0
End Sub
Sub UpdateDisplay(dblValue)
`Author: New Technology Solutions, Inc.
`Purpose: Refresh the display
`5/1/96 Original
Dim MyForm
Set MyForm = Document.frmCalculator
MyForm.lblDisplay.Caption = dblValue
End Sub
-->
</SCRIPT>
<SCRIPT LANGUAGE="VBScript">
<!--
`Author: New Technology Solutions, Inc.
`Purpose:
`All of these routines handle the
`user-defined storage variable
`5/1/96 Original
Sub btnMemRecall_OnClick
dblDisplay = dblMemory
Call UpdateDisplay(dblDisplay)
End Sub
Sub btnMemMinus_OnClick
dblMemory = dblMemory - dblDisplay
End Sub
Sub btnMemPlus_OnClick
dblMemory = dblMemory + dblDisplay
End Sub
-->
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<FORM NAME="frmCalculator">
<!--
This HTML builds the actual calculator form
-->
<TABLE BORDER=2 CELLSPACING=0 CELLPADDING=0 WIDTH=250>
<TR>
<TH COLSPAN=5>
<!--
This is the label for displaying the results
-->
<OBJECT
CLASSID=
"clsid:99B42120-6EC7-11CF-A6C7-00AA00A47DD2"
ID="lblDisplay" WIDTH=250 HEIGHT=30>
<PARAM NAME="Caption" VALUE="0">
<PARAM NAME="Alignment" VALUE="1">
<PARAM NAME="ForeColor" VALUE="#000000">
</OBJECT>
</TH>
</TR>
<TR>
<TD>
<INPUT TYPE="BUTTON" NAME="btnSeven"
VALUE="7" OnClick="Call NumPad(7)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnEight"
VALUE="8" OnClick="Call NumPad(8)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnNine"
VALUE="9" OnClick="Call NumPad(9)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnMultiply"
VALUE="X" OnClick="Call OperationPad(3)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnClear"
VALUE="Clear">
</TD>
</TR>
<TR>
<TD>
<INPUT TYPE="BUTTON" NAME="btnFour"
VALUE="4" OnClick="Call NumPad(4)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnFive"
VALUE="5" OnClick="Call NumPad(5)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnSix"
VALUE="6" OnClick="Call NumPad(6)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnMinus"
VALUE="-" OnClick="Call OperationPad(2)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnMemRecall"
VALUE="MR">
</TD>
</TR>
<TR>
<TD>
<INPUT TYPE="BUTTON" NAME="btnOne"
VALUE="1" OnClick="Call NumPad(1)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnTwo"
VALUE="2" OnClick="Call NumPad(2)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnThree"
VALUE="3" OnClick="Call NumPad(3)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnDivide"
VALUE="/" OnClick="Call OperationPad(4)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnMemMinus"
VALUE="M-">
</TD>
</TR>
<TR>
<TD>
<INPUT TYPE="BUTTON" NAME="btnZero"
VALUE="0" OnClick="Call NumPad(0)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnDecimal"
VALUE=".">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnEquals"
VALUE="=">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnPlus"
VALUE="+" OnClick="Call OperationPad(1)">
</TD>
<TD WIDTH=50>
<INPUT TYPE="BUTTON" NAME="btnMemPlus"
VALUE="M+">
</TD>
</TR>
</TABLE>
</FORM>
</CENTER>
</BODY>
</HTML>