Schongar P.VBScript unleashed.1997
.pdfTabStrip1_Click(0)
End Sub
Finally, the actual unit conversions take place every time the user clicks on the corresponding Command button. The subroutines behind each Command button could be long Select Case statements (or series of If statements), but a simpler and more elegant way of converting the units exists. The conversion factor for each unit is always stored in the caption of the corresponding label in the second column. You can extract this number from the label's Caption property and use it in the calculations. The result is a short subroutine that is totally independent of the converted units. The program reads the conversion factor from the corresponding label and then the number of units (the number entered by the user in the appropriate TextBox control). Then it multiplies the two values (units times conversion factor) and stores the result to the other TextBox control (in the column with the results). You can add more tabs to the control or change the units on each page, and you won't have to touch the code. It will always work, as long as the conversion can be carried out with a simple multiplication. Here's the code behind the first Command button:
Sub CommandButton1_Click()
If NOT IsNumeric(From1.Text) Then Exit Sub
SpacePos=Instr(Unit21, " ")
factor=left(Unit21, SpacePos-1)
To1.Text=CDbl(From1.Text) * factor
End Sub
The code behind the remaining Command buttons is nearly identical, except for the names of the From and To TextBox controls. The first line makes sure the TextBox contains a valid number; if not, the execution of the subroutine is aborted. Then, it isolates the first element in the string, which is the conversion factor, and assigns it to the factor variable. This variable gets multiplied by the contents of the first TextBox, and the result is assigned to the second TextBox.
To run and test your application, save the layout as Conversions.alx, open a new HTML file, and insert the layout with the Insert HTML Layout command on the Edit menu. After the insertion of the HTML layout, the new document will display as follows:
<HTML>
<HEAD>
<TITLE>New Page</TITLE>
</HEAD>
<BODY>
<OBJECT CLASSID="CLSID:812AE312-8B8E-11CF-93C8-00AA00C08FDF"
ID="conversions_alx" STYLE="LEFT:0;TOP:0">
<PARAM NAME="ALXPATH" REF VALUE="file:C:\WINDOWS\Desktop\Projects \Calc\conversions.alx">
</OBJECT>
</BODY>
</HTML>
Notice that the ActiveX Control Pad inserted the complete path name in the definition of the HTML Layout object. If your HTML files and the layouts they contain are stored in the same folder, you should edit the HTML file and remove the path name, or replace it with a relative path, such as ..\Layouts\Conversions.alx.
A Financial Calculator
In this and the following section, you build two calculators: a financial one and a simple math calculator. Calculators, among the most common utilities in every environment, certainly have their place on the Web. The financial calculator is a simple application that enables you to enter the various parameters of a loan (starting and ending dates, amount, interest rate, and monthly payment) and calculates the one you haven't specified. For example, you can enter the amount, the duration, and the interest rate; then ask the program to calculate your monthly payment. Or, instead of the loan's duration, you can enter the monthly payment you can afford to pay, and the program will calculate how long it will take you to pay off the loan. This example can begin as a starting point for a more advanced financial calculator. As usual, the calculations are simple (provided you know about loans, mortgages, and so on), but you will see a few interesting points about VBScript's date manipulation functions demonstrated in this example. Financial calculations rely on date manipulation operations, and VBScript's date functions can simplify your code a good deal.
The User Interface
The user interface of the Financial Calculator application appears in Figure 23.5. It's much simpler than the one from the previous example and should be fairly easy to implement. It consists of five Label controls and five TextBox controls next to them. The user may enter values in some of the TextBox controls and then click the Command button next to the quantity to be calculated. Even if the corresponding box contains a value from previous calculations, the program will ignore it and calculate based on the values of the other controls.
Figure 23.5 : The Financial Calculator utility calculates the duration of a loan, or the monthly payment, according to
the date you provide.
The application has straightforward code, except perhaps for the actual calculations. The functions that calculate the loan's parameters are a bit involved, but the goal here is not to teach you the secrets of banking. If you develop financial applications, you will find the calculations trivial. Even if you've never written any financial applications in the past, you can still follow this example. Just treat the CalculatePayment() and CalculateMonths() functions as black boxes, which calculate the loan's monthly payment and duration in months, respectively. The goal of this project is to show you a few interesting VBScript programming techniques, and not teach you how to calculate loans. The duration of a loan's amortization is calculated with the formula:
MPay=LoanAmount * RRate / (1-(1+RRate)^-N))
where MPay is the monthly payment, LoanAmount is the principal (the loan's initial amount), N is the loan's duration
in months and RRate is given by
RRate=Interest/1200
where Interest is the interest rate. To calculate the duration of the loan in months, the previous equation is solved for
N.
With the calculations out of the way, we can concentrate on the application's user interface, by adding some flexibility to it. The user will have the option to enter either the duration of the loan (in months) or the ending date. If the user supplies the duration of the loan, the starting date field will be ignored. If, however, the user wants to calculate the duration of the loan and has entered a starting date, the program will display the ending date.
VBScript Date Functions
Before understanding the actual code of the application, you should review the VBScript date manipulation functions. The Date and Time functions return the current date and time, respectively, and the Now function returns both date and time. The Date function will get used from within the window's OnLoad event to display the current date in the
Starting Date field:
Sub window_OnLoad()
Date1.Text=Date
End Sub
Date calculations have been a sore point in programming for many years and with nearly every language. The built-in support for manipulating dates was minimal, and programmers had to supply lengthy procedures for operations, such as the difference between two days, or to calculate the date 60 days from today. VBScript simplifies date manipulation with the DateValue() and SerialDate() functions. The DateValue() function accepts a date value as an argument and returns a numeric value, which represents the date. Using the DateValue() function, you can perform arithmetic operations with dates. For example, to calculate the number of days between two dates, you can use the following statements:
date1="3/8/95"
date2="9/21/97"
Difference=DateValue(date2)-DateValue(date1)
(The value of the Difference variable after the execution of the previous lines becomes 928.) If you attempt to subtract two dates directly, you get an error message instead.
The DateSerial() function accepts three numeric arguments that correspond to a year, a month, and a day value and returns the corresponding date. The statement
MsgBox DateSerial(1995, 10, 3)
will display the string 10/3/95 in a message box.
Like the DateValue() function, the DateSerial() function can handle arithmetic operations with dates. For example, you can find out what date it will be on the 90th day of the year by calling DateSerial with the following arguments:
DateSerial(1996, 1, 90)
(30/3/96, if you are curious). To find out the date 1,000 days from now, call the DateSerial() function as
DateSerial(Year(Date), Month(Date), Day(Date)+1000)
You can also add (or subtract) a number of months to the month argument and a number of years to the year argument. Say that the duration of a loan made on August 23, 1996 goes 75 months. You can calculate the exact day of the loan's final payment with the statement
FinalDate=DateSerial(1996, 8+75, 23)
The variable FinalDate is a date variable (11/23/2002, to be exact). Because hardcoding data does not represent a good programming technique, a more complicated statement that enables you to calculate the date M months from today appears next:
NewDate=DateSerial(Year(Date), Month(Date)+M, Day(Date))
where M is the number of months between the two dates; it can be negative, too, if you want to calculate a date in the past.
TIP
VBScript provides two similar functions for manipulating time: the TimeValue() and TimeSerial() functions. These functions won't be used in this example, but they function identically to the date functions, except that they use hours, minutes, and seconds, instead of years, months, and days.
With this background on the VBScript date functions, you can examine the Financial Calculator application. The user interface is quite simple. You must place five Label and five Textbox controls next to each other, and two Command buttons next to the Ending Date and Monthly Payment fields. The labels indicate the type of input that each TextBox accepts. The user must supply a date to all fields that don't have a Command button next to them and to one of the other two. Then, the user may click one of two Command buttons to calculate the ending date or the monthly payment for the specified amount.
Notice that users can enter not only the duration of the loan in months, but they can enter an ending date, too. The
program will use the duration of the loan in the first case, and it calculates the duration by subtracting the starting date from the ending date in the second case. The result also gets displayed in two formats. If the Starting Date field has no information, the program prints the duration of the loan in months. If the Starting Date field contains a valid date, the program displays the ending date.
Programming the Application
Now you can look at the code of the application. The code behind the Click event of the two Command buttons remains quite simple:
Sub CalcMonths_Click()
PayMonths=Int(CalculateMonths()+0.5)
if IsDate(Date1.Text) Then
Date2.Text=DateSerial(Year(Date1.Text), Month(Date1.Text) +PayMonths,
Day(Date1.Text))
Else
Date2.Text=PayMonths
End If
End Sub
Sub CalcPayment_Click()
MPayment.Text=Int((CalculatePayment()+0.5)*100)/100
End Sub
The CalcMonths Command button calls the CalculateMonths()function, which reads the data from the controls and calculates the duration of the loan. Then it displays the duration in the third TextBox in two different formats, depending on the contents of the first TextBox. If the first TextBox control contains a valid date, the result appears as a date. The CalculateMonths() function returns the duration of the loan in months, and the program figures out the date so many months from the starting date by adding the duration of the loan to the starting date; then the program displays it. If the first TextBox doesn't contain a valid date, the duration is displayed in months.
The CalcPayment Command button calls the CalculatePayment() function, which also reads the data from the controls and calculates the monthly payment. The amount of the monthly payment is rounded to two decimal digits and displays on the last TextBox.
Both the CalculateMonths() and CalculatePayment() functions assume that the interest is compounded daily. The actual calculations don't matter for the example. If you make your living by approving loans, you should double check the program, or supply your own functions for calculating the loan parameters. The CalculateMonths () function appears next:
Function CalculateMonths()
MPay=MPayment.Text
LoanAmount=Amount.Text
IRate=Rate.Text
RRate=IRate/1200
If LoanAmount*RRate/MPay >= 1 Then
MsgBox "Too small monthly payment for the amount requested"
CalculateMonths=0
Exit Function
End If
T1=log(1-LoanAmount*RRate/MPay)
T2=log(1+RRate)
CalculateMonths=-T1/T2
End Function
Notice the If statement that compares the quantity LoanAmount*RRate/Mpay to 1. If this quantity is larger than 1, the argument of the logarithm in the formula for calculating T1 is negative, and the logarithm of a negative number can't be calculated. To prevent an error message, make sure that the logarithm can be computed before going to this line. If the arguments are such that the logarithm of the quantity 1-LoanAmount*RRate/Mpay can't be calculated, the function ends prematurely and returns the value zero. In practice, this result will happen if you attempt to pay off a loan with a monthly payment that doesn't even cover the monthly interest. The monthly payment should be such that the total amount you owe to the bank (principal and interest) decreases every month. Otherwise, you have made a loan that will never be paid off, and then why bother making payments?
The CalculatePayment() function starts by computing the duration of the loan and then proceeds with the calculations. The DateDifference() function reads the values of the controls and returns the duration of the loan in months (you see shortly the implementation of the DateDifference() function). This number then gets used in the calculations of the monthly payment.
Function CalculatePayment()
Duration=DateDifference()
If Duration<0 Then Exit Function
LoanAmount=Amount.Text
IRate=Rate.Text
RRate=IRate/1200
MPay=LoanAmount*RRate/(1-(1+RRate)^(-Duration))
CalculatePayment=MPay
End Function
The DateDifference() function is the most interesting one in this application. It uses the DateValue() function to compute the difference between the starting and ending dates in months and returns this value to the calling program. First, it checks the contents of the Date2 TextBox control to see if it contains a valid date. If the user has specified the ending date of the loan instead of its duration, the program subtracts the two dates and divides the result by 30 to come up with the duration of the loan in months. If the Date2 field contains a number, the program uses this value as the duration of the loan. Finally, if the Date2 field contains neither a date nor a numeric value, the program lets the user know he has made an invalid entry, and then doesn't proceed with the calculations. The following text shows the code for the DateDifference() function.
Function DateDifference()
Difference=-1
If IsDate(date2) then
Difference=int((DateValue(Date2)-DateValue(Date1))/30+0.5)
Else
if IsNumeric(date2) then
Difference=date2
else
MsgBox "Please enter a valid ending date or a duration for the loan"
End If
End If
DateDifference=Difference
End Function
A Math Calculator
The last example in this chapter is a math calculator. As you probably expect, the code for carrying out the operations represents the simplest part of the application. This calculator only performs basic arithmetic operations, such as addition and subtraction; however, it's not a trivial application. As you will see, the application has a design you can easily expand and customize. After looking at the code of the application, you build a hexadecimal calculator based on this example by adding a few lines of code.
The User Interface
The application is called Calculator, and its user interface appears in Figure 23.6. The calculator has a Label control display, which means that users can't enter data by typing it. They must click the calculator's buttons with the mouse. In addition to the 10 digits, the period, and the usual arithmetic operators, a few additional buttons exist for keeping running totals. The M+ button adds the current number (the number currently displayed) to a running total in memory, the MR button recalls the total from the memory, and the MC button resets the memory.
Figure 23.6 : The Calculator utility mimics a hand-held calculator from within any Web page.
The user interface of the Calculator application might seem trivial, but it will take you a while. To speed things up, design one Command button for a digit, set its size, font, and any other common properties; then copy and paste it on the layout over and over. Just change the Caption property of each new Command button pasted. Once all the buttons appear on the layout, use the Align commands of the Format menu to align the Command button controls (refer to Figure 23.6). If you don't like this arrangement, place the buttons in a way that suits you.
There are situations in which you may have to align a large number of controls on a layout, like the command buttons of the Calculator application. To align a large number of controls in a tabular arrangement on a layout, you must first make all the controls the same size, then make the horizontal and vertical spacing between adjacent controls the same and finally, adjust the lefts of the controls on the same column, and the tops of the controls on the same row.
Select all the controls you want to align with the mouse while holding down the Shift key. You can also select multiple controls by drawing a rectangle that encloses all the controls you want to adjust with the mouse. Then select the Make Same Size command of the Format menu.
Next, select all the buttons of the first row and align their tops with the Align/Tops command of the Format menu. Then make the spacing between pairs of adjacent buttons the same, using the Horizontal Spacing/Make Equal command from the Format menu. Do the same with the buttons in the first column. This time, align their left sides and make the vertical spacing the same. Once the buttons of the first row and column are in place, you can easily align the rest of them. Select all the button in each row and align their tops, and select all buttons in each column and align their left sides. Just make sure that the first button you select has the alignment you want applied to the other ones.
Programming the Application
The code of the Calculator application mimics the operation of a hand-held calculator. It expects the user to type a number (the first operand), then the symbol of an operation (the operator), and then another number (the second operand). These three entities then get combined to produce the result as follows:
result=operand1 operator operand2
As the user clicks on digit buttons, the corresponding digit displays. This result occurs by appending the new digit to the label's Caption property. When the user clicks an operator's button, the current number is stored in a global variable, and the display clears in anticipation for the second operand. The subroutine for the Command button's Click event is
Sub Digit1_Click()
DisplayDigit("1")
End Sub
The subroutines for the click events of the other digit buttons are similar.
The DidplayDigit() subroutine does more than just append a digit to the display. It checks the global variable MustClear to see if the display must be cleared first:
Sub DisplayDigit(digit)
If MustClear Then
Display.Caption=""
MustClear=False
End If
Display.Caption=Display.Caption+digit
End Sub
The variable MustClear is set to True every time an operator's button is clicked. Say the user enters the number 381 and then clicks the Addition button to signal the intention to add two numbers. The display doesn't clear immediately after the Plus button gets clicked. Instead, the MustClear variable is set to True and the display actually clears only when the user clicks the next digit button (the first digit of the second operand). The code for the Plus button's Click event appears next:
Sub Plus_Click()
op1=Display.Caption
MustClear=True
op="PLUS"
End Sub
op1 and op are global variables, whose values are set by the various subroutines of the application; they get used during the calculation of the result. When the user clicks the Plus button, the contents of the display become the first operand, the operator is set according to the button that was pressed, and the MustClear variable is set to True. This variable must be set to True so that the next time the user clicks a digit button, the display clears and a new number is entered.
All the action takes place from within the Equals button's Click event. That subroutine appears in the following code:
Sub Equals_Click()
Op2=Display.Caption
Select Case Op
Case "PLUS":
result = CDbl(op1) + CDbl(op2)
Case "MINUS":
result = CDbl(op1) - CDbl(op2)
Case "TIMES":
result = CDbl(op1) * CDbl(op2)
Case "DIV":
If CDbl(op2) = 0 Then
Display.Caption="ERROR!"
Else
result = CDbl(op1) / CDbl(op2)
End If
End Select
If Display.Caption<>"ERROR!" then Display.Caption=result
MustClear=True
End Sub
As soon as the Equals button is clicked, the number currently displayed becomes the second operand and the program checks the value of the op variable. If op is PLUS, it adds the two operands. If it is MINUS, the program subtracts the second from the first operand. If op is TIMES, it multiplies the two operands. In all cases, the result is stored in the result variable and gets displayed later.
If the value of the op variable is DIV, however, the program tests the value of the second operand against zero to prevent a runtime error (the Division by zero error). If the second operand is non-zero, it performs the division and displays the result. If it is zero, the program displays the string ERROR! instead of the result.
Finally, the memory buttons manipulate the contents of another global variable, the memory variable. The M+ button adds the current number to the memory variable, the MR button displays the current value of the memory variable, and the MC button resets the value to zero. The three subroutines appear next:
Sub MemAdd_Click()
memory=memory + Display.Caption
MustClear=True
End Sub
Sub MemRecall_Click()
Display.Caption=memory
