|  | Click Here!

Search the site:
EXPERT SEARCH

| Programming Languages
| Databases
| Security
| Web Services
| Network Services
| Middleware
| Components
| Operating Systems
| User Interfaces
| Groupware & Collaboration
| Content Management
| Productivity Applications
| Hardware
| Fun & Games

EarthWeb sites
Crossnodes
Datamation
Developer.com
DICE
EarthWeb.com
EarthWeb Direct
ERP Hub
Gamelan
GoCertify.com
HTMLGoodies
Intranet Journal
IT Knowledge
IT Library
JavaGoodies
JARS
JavaScripts.com
open source IT
RoadCoders
Y2K Info

# Chapter 23

# Conversions and Calculations

by Evangelos Petroutsos

CONTENTS

- Metric Conversions
  - The User Interface
  - The `TabStrip` Control
  - Implementing the Conversions Utility
  - Programming the Application
- A Financial Calculator
  - The User Interface
- A Math Calculator
  - The User Interface
  - Programming the Application
  - Improving the Calculator
  - Further Improvements
- Review

The last part of the book contains a collection of examples you will find useful both in learning VBScript and applying it to your projects. These examples demonstrate key features of the language, some of them rather trivial and others more advanced. All the examples in this section were designed to show how to handle common situations in application development with a language like VBScript, as well as how to use some of the more advanced ActiveX controls. Converting metric units, for instance, is a trivial operation that can be carried out with a single multiplication. The Conversions utility of the next section, however, deploys an elaborate user interface based on the `TabStrip` control. In the discussion of the examples, you will see how this control is used in building a user interface. Even if you're not interested in learning how to write calculators, in the following chapters you will certainly find useful and practical information and VBScript programming techniques.

The first example of this chapter discusses a unit conversion utility. As simple as the actual conversions may be, the program was designed so that you can easily expand it to perform additional conversions. The second example is a financial calculator. Again, the main topic isn't the actual code for calculating monthly payments, but how to manipulate dates programmatically, a common task in financial calculations. The last example in this chapter is a math calculator. You will see the basics for developing a calculator that performs the basic arithmetic operations, and you learn how to simulate a hand-held calculator. Again, this application was designed so that it can be easily expanded, and you will see how to enhance the basic calculator by making it capable of manipulating hexadecimal numbers.

## Metric Conversions

The first example presents a utility that converts metric units. The actual calculations are trivial, but the example provides a few programming issues to explore. The first issue is the user interface. As you can see in Figure 23.1, the Conversions utility deploys a sophisticated user interface based on the `TabStrip` control. You could have designed this application in many different ways, but the one suggested here has distinctive advantages.

Figure 23.1 : The Conversions utility lets the user convert different types of units, grouped by category.

### The User Interface

First, the application's window stays quite small. Placing all the units on a single layout would result in a waste of valuable screen estate, not to mention that you can fit only so much in a window.

By grouping the various units as Figure 23.1 shows, the application becomes easier to use. People usually want to convert specific units from one system to another; they don't convert units at large, just for the sake of it. The user of the Conversions application will activate the appropriate tab and see on it the units he or she wants to convert.

Finally, once you have implemented the application, you can easily add tabs to accommodate other types of units. You just repeat the existing code and replace the prompts on the layout.

The Conversions application relies on the `TabStrip` control, which comes with Internet Explorer 3.0 and is one of topics discussed in this chapter. The `TabStrip` control is a collection of tabbed pages that contain related information. Each page in a `TabStrip` control contains identically structured information corresponding to a different group. If you wanted to display statistical data about various cities on a `TabStrip` control, you would use a different page per city. The structure of the data for each city is the same, just the data is different. In other words, all pages will contain the same controls, but different data. Of course, you can have variations on the basic structure of the data displayed on a `TabStrip` control. For instance, some cities may have unique features that must be displayed on separate controls, which will be visible on certain tabs and invisible on others.

### The `TabStrip` Control

Now start by designing the application's user interface with the ActiveX Control Pad. Start with Control Pad, select New HTML Layout from the File menu, and when the new Layout appears on-screen, select the `TabStrip` tool and draw a relatively large `TabStrip` control on the Form. When you place a new `TabStrip` on an HTML Layout, it has two tabs, named `Tab1` and `Tab2`. To change their names or add new tabs, right-click one of the tabs, and the shortcut menu seen in Figure 23.2 appears. The four commands on this shortcut menu enable you to

Figure 23.2 : To add, remove, or rearrange the tabs on a TabStrip control, right-click one of the tabs, and you see this shortcut menu.

- Insert a new tab at the location of the current tab.
- Delete the current tab.
- Rename the current tab.
- Move the current tab to another location. If you choose Move, you'll be presented with a list of the tabs on the control. Select the tab you want to relocate and move it up and down the list.

Create an additional tab and name the three tabs `Length`, `Weight`, and `Area`. (Refer back to Figure 23.1.)

#### `TabStrip` Control's Properties

You can also adjust the appearance of the tabs on the `TabStrip` control using the Properties window. The `Style` property determines the look of the tabs and can have one of the following values (see Figure 23.3):

Figure 23.3 : There are three styles you can choose for your TabStrip control.

> 0 (default): Each page is identified with a tab.

> 1: Each page is identified with a button.

> 3: Pages have no marks on them.

Figure 23.3 illustrates the three possible values of the `Style` property. If the `Style` property is 0, you must select the page to appear on top of the others programmatically. If the control contains too many pages and their tabs, or buttons, can't be displayed in a single row, two buttons with arrows to the left and right are automatically attached next to the tabs; these arrows enable users to scroll and locate the one they need. If you prefer, you can set the `MultiRow` property to `True`, to make all tabs visible, even if they have to occupy multiple lines. This arrangement works in address book types of applications, as shown in Figure 23.4. The tabs on the `TabStrip` control of Figure 23.4 appear to the right side of the control by setting the `TabOrientation` to 3 (Right). The other values of the `TabOrientation` property are 0 (top), 1 (bottom), and 2 (left).

Figure 23.4 : The TabStrip control is ideal for address book types of applications.

Finally, you can set the width and height of each tab with the `TabFixedWidth` and `TabFixedHeight` properties respectively (both properties are expressed in pixels). By default, each tab can have its own dimensions, depending on the caption displayed. To set all tabs to the same width, set these two properties to a value large enough to accommodate all the tabs.

#### `TabStrip` Control's Methods

So far you have seen the properties for adjusting the appearance of the control at design time. To control the `TabStrip` programmatically, you must first understand the nature of this control, which is a bit unusual. The `TabStrip` control represents a collection of `Tab` objects, and each `Tab` object in the collection has its own index in the `Tabs` collection. `Tabs` is an array, whose elements are the individual tabs. To access the first tab and read or set its properties with VBScript commands, use the expression

>     TabStrip1.Tabs(0)

where `TabStrip1` is the name of the control. The second tab has index 1, and so on.

The `Tabs` collection has a single property, `Count`, which returns the total number of tabs. To manipulate the control's tags at runtime, the `Tabs` collection provides four methods, which correspond to the commands of its shortcut menu. (See Figure 23.2.) The `Tabs` collection's methods are

> Add adds a new tab to the `Tabs` collection.
> Clear removes all objects from the `Tabs` collection.
> Item returns a member of the `Tabs` collection.
> Remove removes a `Tab` object from the collection.

To add a new tab at runtime, use a statement like

>     Set TabObject = TabStrip1.Tabs.Add([ Name [, Caption [, index]]])

where `TabStrip1` is the name of the control and the bracket indicates that the arguments enclosed are optional. The simplest form of the `Add` method is

>     TabStrip1.Tabs.Add

which appends a new tab to the control and names it `Tabx`, where `x` is a number. If the control already has 2 tabs, `Tab1` and `Tab2`, the previous call to the `Add` method will add a third one and name it `Tab3`. You can specify the name, caption, and order of the tabs added to the collection.

The `Clear` method removes all the tabs from the control, similar to the `Clear` method of the `ListBox` control, which removes all items in a `List` control. The `Remove` method removes a `Tab` object from the collection, and its syntax is

>     TabStrip1.Tabs.Remove(index)

where `index` is the order of the tab to be removed in the collection. The statement

>     TabStrip1.Tabs.Remove(0)

removes the first tab of the `TabStrip1` control.

Finally, the `Item` method returns a member of the `Tabs` collection, and its syntax is

>     Set ThisTab = TabStrip1.Tabs.Item(index)

The `Caption` property controls the string that identifies each member of the Tabs collection. To set the caption of the first tab in the `TabStrip1` control, you can use the statement

>     TabStrip1.Tabs(0).Caption = "Printers"

or extract the appropriate member of the collection and then set the property:

>     ThisTab=TabStrip1.Tabs(0).Item

>     ThisTab.Caption = "Printers"

### Implementing the Conversions Utility

Place a `TabStrip` control on the layout and add a third tab with the `Add` command of the shortcut menu. Then change the captions of all three tabs to match the ones shown in Figure 23.1. To change the font of the captions, right-click the control and select properties from the shortcut menu that will appear. In the Properties window, set the `Font` property to the appropriate value.

Now you're ready to place the various controls on the `TabStrip` control. The controls aren't really placed on the `TabStrip` control. Instead, they are placed on the layout and the `TabStrip` control enables them to appear. You can draw each one of the controls on the Layout outside the `TabStrip` control and then move them with the mouse to their places. You can also move the `TabStrip` control out of view while creating the rest of the user interface, and then place it on top of the controls and resize it. If the `TabStrip` hides the remaining controls, place it behind the other controls with the Send to Back command of the Format menu.

The box on which the conversion factors are placed is an `ImageBox`. The `ImageBox` control contains eight labels in two columns: the Label controls of the first column are named `Units11`, `Units12`, `Units13`, and `Units14`, and the labels of the second column are named `Units21`, `Units22`, `Units23`, and `Units24`. They hold the conversion factors for various pairs of units. The captions of these labels must change every time the user clicks a different tab, so they must be set from within the code. Don't bother to change them at this point. Just notice that the captions of the labels in the first column are left-aligned, and those of the second column are right-aligned.

Then, place the `TextBox` controls where the user will enter the amounts to be converted. Place the Command buttons and the `TextBox` controls where the results will be displayed. The `TextBox` controls on the first column are named `From1`, `From2`, `From3`, and `From4`, and the controls on the second column are named `To1`, `To2`, `To3`, and `To4`. These text boxes hold the units to be converted and the equivalent amount in the new system. Place all the controls on the form, align them with the commands of the Format menu, and assign a common font name and size for them all.

### Programming the Application

Now you can look at the code of the application. First, you must supply the subroutine that changes the captions of the `Label` controls. This subroutine must be invoked every time the user clicks a tab, an action signaled by the `TabStrip` control's `Click` event. The subroutine for this event provides an argument, which is the index of the tab that was clicked. Depending on the value of the `Index` argument, the captions are set to different values:

>     Sub TabStrip1_Click(Index)

>         If Index=0 Then

>             Unit11.Caption="1 inch (in)"

>             Unit12.Caption="1 foot (ft)"

>             Unit13.Caption="1 yard (yd)"

>             Unit14.Caption="1 mile (mi)"

>             Unit21.Caption="2.54 cm"

>             Unit22.Caption="0.3048 m"

>             Unit23.Caption="0.9144 m"

>             Unit24.Caption="1.6093 km"

>             ClearBoxes

>         End If

>         If Index=1 Then

>             Unit11.Caption="1 sq. inch"

>             Unit12.Caption="1 sq. foot"

>             Unit13.Caption="1 sq. yard"

>             Unit14.Caption="1 acre"

>             Unit21.Caption="6.4526 sq. cm"

>             Unit22.Caption="0.093 sq. m"

>             Unit23.Caption="0.8361 sq. m"

>             Unit24.Caption="4046.86 sq. m"

>             ClearBoxes

>         End If

>         If Index=2 Then

>             Unit11.Caption="1 ounce (oz)"

>             Unit12.Caption="1 pound (lb)"

>             Unit13.Caption="1 short ton"

>             Unit14.Caption="1 long ton"

>             Unit21.Caption="28.35 gr"

>             Unit22.Caption="0.4536 kg"

>             Unit23.Caption="0.9072 t"

>             Unit24.Caption="1.0161 t"

>             ClearBoxes

>         End If

>     End Sub

The `ClearBoxes()` subroutine clears the contents of the `TextBox` controls every time a new tab is displayed, because the amounts converted earlier wouldn't agree with the new units on the page. This subroutine takes care of all the elements that change as the user switches to a different page. When the layout is loaded for the first time, this subroutine must also be called, or else the labels will be blank until the user actually clicks on one of them. In the `window_OnLoad` event, enter the following lines:

>     Sub Window_onLoad()

>         TabStrip1_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

>         MustClear=True

>     End Sub

>     Sub MemClear_Click()

>         memory=0

>         MustClear=True

>     End Sub

The code of the Calculator application is fairly straightforward. The actual calculations only require a few lines of code, and most of the code handles the display. You can easily expand the bare bones application presented here to include more operations. For example, you can add a +/- button that inverts the sign of the current number. This button can be implemented with a single line of code:

>     Display.Caption="-" & Display.Caption

### Improving the Calculator

You can easily turn this utility into a scientific calculator. You will spend the most time adjusting the user interface to include more buttons, because the operations are straightforward. For instance, if you add a COS button (for calculating the cosine of a number) on the layout, you must enter the following line in the button's `Click` event:

>     Display.Caption=cos(CDbl(Display.Caption))

When the user clicks the COS button, the cosine of the displayed value is calculated and appears on the calculator's display. You can add trigonometric functions, square roots, and powers, because these operations don't require two operands. They just read the current value, calculate a function of the number and display the result. You must, however, add a good deal of error checking code so that the program won't attempt to calculate the square root or logarithm of a negative number.

Another useful variation of the basic Calculator application is a hexadecimal calculator, like the one shown in Figure 23.7. If you add a few more buttons for the hexadecimal digits `A` through `F`, you can perform the same operations, only in the hexadecimal number system. In the hexadecimal system, however, you can work with integers only. To perform operations in the hexadecimal system, you must prefix the numbers with the symbols `&H` and then take their value with the `CInt` function, which converts its argument to an integer. The arithmetic operations will be carried out in the decimal system and the result gets converted to the hexadecimal system with the function `Hex`.

The HexCalculator application, shown in Figure 23.7, is a variation on the Calculator that performs hexadecimal calculations. The `Equals_Click()` subroutine looks slightly different than before:

>     Sub Equals_Click()

>         Op2="&H" & Display.Caption

>         Select Case Op

>         Case "PLUS":

>             result = CInt(op1) + CInt(op2)

>         Case "MINUS":

>             result = CInt(op1) - CInt(op2)

>         Case "TIMES":

>             result = CInt(op1) * CInt(op2)

>         Case "DIV":

>             if CInt(op2) = 0 Then

>                 Display.Caption="ERROR!"

>             else

>                 result = CInt(op1) / CInt(op2)

>             End If

>         End Select

>         If Display.Caption<>"ERROR!" then Display.Caption=Hex(result)

>         MustClear=True

>     End Sub

When you prefix the operands with the `"&H"` string, they get converted to hexadecimal numbers. The `CInt()` function converts these hex numbers to decimals, performs the operation, and then converts the result back to a hex number before displaying it.

### Further Improvements

As you can see, it didn't take much to convert the simple decimal calculator into a hexadecimal one. To summarize, all you had to do was add the extra hex digits, convert the arguments to decimal numbers to carry out the calculations, and then convert the result back to a hexadecimal number to display the result. You can now try to combine both calculators in one by adding a toggle button that switches the mode of the calculator between the two systems. When the calculator is in decimal mode, you should disable the hex digits on the layout and restore them when the calculator is switched back to hexadecimal mode. As far as the calculations are concerned, you can copy both subroutines for the Equals button we presented earlier in your code and call one of them, depending on the calculator's current mode.

## Review

In this chapter's examples you were shown how to design applications that perform simple calculations, like converting units between systems, or more complicated calculations like math operations. As you have realized by now, the functions that do the actual calculations are usually the shortest and simplest part of the application. The real challenge in programming in a visually rich environment like Windows 95 is to provide the simplest, most functional user interface. This requires visual design skills, as well as programming skills.

The code behind the various buttons of the Calculator application wasn't simple, considering what it accomplishes. Arranging the buttons on the layout and coming up with an attractive user interface will probably take you longer than writing the code. After the code of the Calculator application was written, it was surprisingly simple to add support for hexadecimal digits to the application, as well as extend it to handle trigonometric and other advanced math functions.

The Conversions utility is another typical example. Writing the code for converting units between systems is trivial, but with a well-designed user interface we were able to create a usable application (one that doesn't overwhelm the user with options). At the same time, by displaying the conversion factors on the program's form, we were able to design an application that can be expanded without actually touching the code that performs the calculations. You can add more options to the program by simply adding new labels with conversion factors. The logic of converting the units has been built into the application, and you needn't worry about it unless the conversion isn't as simple as a multiplication. The display of the conversion factors on the form not only simplifies the code but provides useful information to the user.

The types of applications we explored in this chapter were rather simple ones, but they are quite common and it's likely that you'll incorporate a similar functionality to some of your applications. No doubt, you've seen numerous applications that perform financial or arithmetic calculations. What will make the difference between yours and the other applications is simplicity and ease of use. Our examples weren't the ultimate examples of simplicity or flexibility, but they demonstrated some of the key features you should incorporate in even the simplest applications.

| Use of this site is subject certain Terms & Conditions. Copyright (c) 1996-1999 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Please read our privacy policy for details.