























Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
This chapter of the book focuses on designing practical Windows applications using Visual Studio 2010 and Visual Basic language. You will learn how to design graphical user interfaces (GUIs) and program events for various controls, such as ComboBox, TextBox, and CheckBox. Additionally, you will discover how to write robust applications with error handling. The document also covers the concept of event-driven programming and the use of prototypes to capture application requirements.
Typology: Schemes and Mind Maps
1 / 31
This page cannot be seen from the preview
Don't miss anything!
























The first three chapters of this book introduced you to the basics of designing applications with Visual Studio 2010 and the components of the Visual Basic language. You know how to design graphical user interfaces (GUIs) and how to use Visual Basic statements to program events for the various controls. You also know how to write functions and subroutines and how to call the functions and subroutines that are built into Visual Basic. In this chapter, you’ll design a few more Windows applications — this time, a few practical applications with more functional interfaces and a bit of code that does something more prac- tical. You’ll put together the information presented so far in the book by building Windows applications with the visual tools of Visual Studio, and you’ll see how the applications interact with users by coding the events of interest. If you are new to Visual Studio, you should design the examples on your own using the instructions in the text rather than open the projects for this chapter (available for download at www.sybex.com/go/masteringvb2010) and look at the code. In this chapter, you will learn how to do the following: ◆ Design graphical user interfaces ◆ Program events ◆ Write robust applications with error handling
As you recall from Chapter 1, ‘‘Getting Started with Visual Basic 2010,’’ the design of a Win- dows application consists of two distinct phases: the design of the application’s interface and the coding of the application. The design of the interface is performed with visual tools and consists of creating a form with the relevant elements. These elements are the building blocks of Windows applications and are called controls. The available controls are shown in the Toolbox and are the same elements used by all Win- dows applications. You can purchase additional controls from third-party vendors or create your own custom controls. After you install third-party or custom controls, they will appear in the Toolbox alongside the built-in controls. In addition to being visually rich, the controls embed a lot of functionality. The TextBox control, for example, can handle text on its own,
130 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING without any programming effort on your part. The ComboBox control expands the list with its items when users click the arrow button and displays the selected item in its edit box. In gen- eral, the basic functionality of the controls is built in by design so that all applications maintain a consistent look. The interface dictates how users will interact with your application. To prompt users for text or numeric data, use TextBox controls. When it comes to specifying one or more of several options, you have many choices: You can use a ComboBox control from which users can select an option, or you can put a few CheckBox controls on a form that users can select or clear. If you want to display a small number of mutually exclusive options, place a few RadioButton controls on the form. Every time the user selects an option, the previously selected one is cleared. To initiate actions, place one or more Button controls on the form. You will learn more about basic Windows controls and their properties in Chapter 5, ‘‘The Basic Windows Controls.’’ Controls expose a large number of properties, which are displayed in the Properties window at design time. You use these properties to adjust not only the appearance of the controls on the form but their functionality as well. The process of designing the interface consists mostly of setting the properties of the various controls. By the way, you can also set the properties of controls through code. The code will take effect in runtime. You will see some examples of such code in the next chapter. An important aspect of the design of your application’s user interface is the alignment of the controls on the form. Controls that are next to one another should be aligned horizontally. Con- trols that are stacked should have either their left or right edges aligned vertically. You should also make sure the controls are spaced equally. The integrated development environment (IDE) provides all the tools for sizing, aligning, and spacing controls on the form, and you’ll see these tools in action through examples in this chapter. By designing the interface you have practically outlined how the application will interact with the user. The next step is to actually implement the interaction by writing some code. The programming model of Visual Basic is event driven: As the user interacts with the controls on your form, some code is executed in response to user actions. The user’s actions cause events, and each control recognizes its own set of events and handles them through subroutines, which are called event handlers. When users click a button, the control’s Click event is fired, and you must insert the relevant code in the control’s Click event handler. The event-driven program- ming model has proven very successful because it allows developers to focus on handling spe- cific actions. It allows you to break a large application into smaller, manageable units of code and implement each unit of code independently of any other. Developing Windows applications is a conceptually simple process, but there’s a methodol- ogy to it and it’s not trivial. Fortunately, the IDE provides many tools to simplify the process; it will even catch most of the errors in your code as you type. You have seen how to use some of the tools of the IDE in the first three chapters. In this chapter, I’ll present these tools through examples.
One easy-to-implement, practical application is a program that calculates loan parameters. Visual Basic provides built-in functions for performing many types of financial calculations, and you need only a single line of code to calculate the monthly payment given the loan amount, its duration, and the interest rate. Designing the user interface, however, takes much more effort.
132 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING Figure 4. LoanCalculator is a sim- ple financial application. To calculate the monthly payments on a loan, we call the built-in Pmt () function, whose syntax is as follows: MonthlyPayment = Pmt(InterestRate, Periods, Amount, FutureValue, Due)
Here’s how the Pmt () function works. The interest rate, argument InterestRate , is spec- ified as a monthly rate. If the annual interest rate is 14.5 percent, the value entered by the user in the Interest Rate box should be 14.5. The user will express the rate as a percentage, but the function accepts the decimal value. To convert percentage to a decimal value, you need to multiply the annual percentage rate by 0.01. Finally, since this is the annual rate and you need a monthly value, you need to divide the value by 12. The mathematical expression for converting the annual interest rate specified by the user to a monthly interest rate accepted by the Pmt() function is: 0.01 * annualInterestRate / 12. In this example, with a 14. annual rate, the monthly rate will be 0.145/12. The duration of the loan, the Periods argu- ment, is specified in number of months, and the Amount argument is the total loan amount. The FutureValue argument is the value of the loan at the end of the period, which should be zero (it would be a positive value for an investment), and the last argument, Due , specifies when payments are due. The value of Due can be one of the constants DueDate.BegOfPeriod and DueDate.EndOfPeriod. These two constants are built into the language, and you can use them without knowing their exact value. The present value of the loan is the amount of the loan with a negative sign. It’s negative because you don’t have the money now. You’re borrowing it — it is money you owe to the bank. Future value represents the value of something at a stated time — in this case, what the loan will be worth when it’s paid off. This is what one side owes the other at the end of the specified period. So the future value of a loan is zero. You don’t need to know how the Pmt () function calculates the monthly payment, just how to call it and how to retrieve the results. To calculate the monthly payment on a loan of $25, with an interest rate of 14.5 percent, payable over 48 months and payments due the last day of the payment period (which in this case is a month), you’d call the Pmt() function as follows: Pmt(0.145 / 12, 48, -25000, 0, DueDate.EndOfPeriod)
BUILDING A LOAN CALCULATOR 133 The Pmt() function will return the value 689.448821287218. Because it’s a dollar amount, you must round it to two decimal digits on the interface. Notice the negative sign in front of the Amount argument in the statement. If you specify a positive amount, the result will be a negative payment. The payment and the loan’s amount have different signs because they represent different cash flows. The loan’s amount is money you owe to the bank, whereas the payment is money you pa y to the bank. The last two arguments of the Pmt() function are optional. The Parameter Info feature of the IntelliSense autocompletion system built into Visual Studio will indicate optional param- eters by placing them inside the square brackets in the Parameter Info pop-up window, as shown here. If you omit optional parameters, Visual Basic uses their default values, which are 0 for the FutureValue argument and DueDate.BegOfPeriod for the Due argument. You can entirely omit these arguments and call the Pmt() function like this: Pmt(0.145 / 12, 48, -25000) Calculating the amount of the monthly payment given the loan parameters is quite simple. For this exercise, what you need to understand are the parameters of a loan and how to pass them to the Pmt() function. You must also know how the interest rate is specified to avoid invalid values. Although the calculation of the payment is trivial, designing the interface will take a bit of effort. You need to make sure the interface is easily understood and intuitive. When the user is confronted with the application, they should be able to guess easily what the application is doing and how they can interact with it. The application should also behave according to the principle of least surprise. For example, if the user presses the Tab button, they expect that focus of the controls will move from right to left or from top to bottom. Also, the user will expect the application to perform basic data validation. If the application detects invalid data, the user will expect that the focus will be set on the control containing the invalid value so that they can immediately correct the entered value. These are just a few example characteristics of well-behaved applications. If you wish to learn more about GUI guidelines that Microsoft recommends for applications running on Windows 7 and Windows Vista, you can download the ‘‘Windows User Experience Interaction Guidelines’’ PDF file from MSDN. You will find the download link at the following URL: http://msdn.microsoft.com/en-us/library/aa511258.aspx. Designing the User Interface Now that you know how to calculate the monthly payment and understand the basics of good interface design, you can design your own user interface. To do so, start a new Windows Forms project, name it LoanCalculator , and rename its form to frmLoan. Your first task is to decide the font and size of the text you’ll use for the controls on the form. The form is the container
BUILDING A LOAN CALCULATOR 135
posed to enter any data in this box, so set the ReadOnly property to True to lock the con- trol and prevent users from entering data. You’ll be able to change its value from within your code, but users won’t be able to type anything in it. (We could have used a Label control instead, but the uniform look of TextBoxes on a form is usually preferred.) You will also notice that the TextBox controls have a 3D frame. Experiment with the control’s BorderStyle property to discover the available styles for the control’s frame (I’ve used the Fixed3D setting for the TextBox controls).
and it appears to the right of the check box. Because we want the titles to be to the left of the corresponding controls, we’ll change this default appearance.
property. Its value is MiddleLeft. If you expand the drop-down list by clicking the arrow button, you’ll see that this property has many different settings, and each setting is shown as a square. Select the button that will center the text vertically and right-align it horizon- tally. The string MiddleRight will appear in the Properties window when you click the appropriate button.
to chkPayEarly.
field.
set its Text property to Monthly Payment.
erty to Exit. Aligning the Controls Your next step is to align the controls on the form. The IDE provides commands to align the controls on the form, all of which can be accessed through the Format menu. To align the con- trols that are already on the form, follow these steps:
for one control whose handles will be white. To specify the control that will be used as a reference for aligning the other controls, click it after making the selection. (You can select multiple controls either by using the mouse to draw a rectangle that encloses them or by clicking each control while holding down the Ctrl button.)
include the check box in this selection.
trols, and its right edge should align with the right edges of the Label controls. In case the resizing markers do not appear on the CheckBox control, set the value of its AutoSize property to False.
! Make Equal. This action will space the controls vertically. Then align the baseline of
136 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING each TextBox control with the baseline of the matching Label control. To do so, move each TextBox control with the mouse until you see a magenta line that connects the baseline of the TextBox control you’re moving and that of the matching Label control. Your form should now look like the one shown in Figure 4.1. Take a good look at it and make sure no controls are misaligned. In the interface design process, you tend to overlook small problems such as a slightly misaligned control. The user of the application, however, instantly spots such mistakes. Programming the Loan Application Now you’ve created the interface, run the application, and seen how it behaves. Next you’ll enter a few values in the text boxes, change the state of the check box, and test the function- ality already built into the application. Clicking the Monthly Payment button won’t have any effect because we have not yet added any code. If this were a prototype you were building for a customer, you would add a statement in the Monthly Payment button to display a random value in the Monthly Payment box. When you double-click the control for the first time, Visual Studio will generate an empty default event handler declaration for you. Next time you double-click the control, Visual Studio will bring you to the event handler. If you’re happy with the user interface, stop the applica- tion, open the form, and double-click the Monthly Payment Button control. Visual Basic opens the code window and displays the definition of the ShowPayment_Click event: Private Sub bttnShowPayment_Click(...) Handles bttnPayment.Click Because all Click event handlers have the same signature (they provide the same two argu- ments), I’ll be omitting the list of arguments from now on. Actually, all event handlers have two arguments, and the first of them is always the control that fired the event. The type of the second argument differs depending on the type of the event. Place the pointer between the lines Private Sub and End Sub, and enter the rest of the lines of Listing 4.1. (You don’t have to reen- ter the first and last lines that declare the event handler.) Listing 4.1: The Code behind the Monthly Payment button Private Sub bttnShowPayment_Click(ByVal (…) Handles bttnShowPayment.Click Dim Payment As Double Dim LoanIRate As Double Dim LoanDuration As Integer Dim LoanAmount As Integer LoanAmount = Convert.ToInt32(txtAmount.Text) LoanIRate = 0.01 * Convert.ToDecimal(txtRate.Text) / 12 LoanDuration = Convert.ToInt32(txtDuration.Text) Dim payEarly As DueDate If chkPayEarly.Checked Then payEarly = DueDate.BegOfPeriod
138 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING Public Enum DayOfWeek Monday Tuesday Wednesday Thursday Friday Saturday Sunday End Enum By using Enum instead of simple constant literal values, you add type safety to your applica- tion. For example, if you define the function that has a day as the DayOfWeek parameter, as in TicketPrice(movie as Movie, day as DayOfWeek) as Decimal, the code that is calling the function will have to pass a value defined in the DayOfWeek enum as a parameter, as in following statement: Dim price = TicketPrice(avatarMovie, DayOfWeek.Saturday) Had you defined the days of the week names as constants, as in following code, you would not be able to perform type checking: Const Monday As String = "Monday" Const Tuesday As String = "Tuesday" Const Wednesday As String = "Wednesday" ’ … Had you no Enum construct in Visual Basic, you would have to resort to constants. When you use constants, the TicketPrice function would have to declare the day parameter as String, meaning that when invoking the function, you could pass just any String value. Using the Enum type, however, you know that value belongs to predefined enumeration. In Listing 4.1, the first line of code within the subroutine declares a variable. It lets the appli- cation know that Payment is a variable for storing a floating-point number (a number with a decimal part) — the Double data type. The line before the If statement declares a variable of the DueDate type. This is the type of argument that determines whether the payment takes place at the beginning or the end of the month. The last argument of the Pmt() function must be a variable of this type, so we declare a variable of the DueDate type. As mentioned earlier in this chapter, DueDate is an enumeration with two members: BegOfPeriod and EndOfPeriod. The first really interesting statement in the subroutine is the If statement that examines the value of the chkPayEarly CheckBox control. If the control is selected, the code sets the payEarly variable to DueDate.BegOfPeriod. If not, the code sets the same variable to DueDate.EndOfPeriod. The ComboBox control’s Checked property returns True if the control is selected at the time and False otherwise. After setting the value of the payEarly variable, the code calls the Pmt() function, passing the values of the controls as arguments: ◆ The first argument is the interest rate. The value entered by the user in the txtRate TextBox is multiplied by 0.01 so that the value 14.5 (which corresponds to 14.5 percent) is passed to the Pmt() function as 0.145. Although we humans prefer to specify interest
BUILDING A LOAN CALCULATOR 139 rates as integers (8 percent) or floating-point numbers larger than 1 (8.24 percent), the Pmt() function expects to read a number that’s less than 1. The value 1 corresponds to 100 percent. Therefore, the value 0.1 corresponds to 10 percent. This value is also divided by 12 to yield the monthly interest rate. ◆ The second argument is the duration of the loan in months (the value entered in the txtDuration TextBox). ◆ The third argument is the loan’s amount (the value entered in the txtAmount TextBox). ◆ The fourth argument (the loan’s future value) is 0 by definition. ◆ The last argument is the payEarly variable, which is set according to the status of the chk- PayEarly control. The last statement in Listing 4.1 converts the numeric value returned by the Pmt() function to a string and displays this string in the fourth TextBox control. The result is formatted appro- priately with the following expression: Payment.ToString("#.00") The Payment variable is numeric, and all numeric variables provide the method ToString, which formats the numeric value and converts it to a string. The character # stands for the integer part of the variable. The period separates the integer from the fractional part, which is rounded to two decimal digits. The Pmt() function returns a precise number, such as 372.2235687646345, and you should round it to two decimal digits and format it nicely before displaying it. For more information on formatting numeric (and other) values, see the section ‘‘Formatting Numbers’’ in Chapter 2, ‘‘VB Programming Essentials.’’ Finally, the formatted string is assigned to the Text property of the TextBox control on the form.
If you didn’t know about the Pmt() built-in function, how would you go about calculating loan payments? Code snippets to the rescue!
Snippet command.
on a Loan. The following code will be inserted at the location of the pointer: Dim futureValue As Double = 0 Dim payment As Double payment1 = Pmt(0.05 / 12, 36, -1000, futureValue, DueDate.EndOfPeriod)
BUILDING A LOAN CALCULATOR 141 Dim LoanIRate As Double Dim LoanDuration As Integer Dim LoanAmount As Integer ‘ Validate amount If IsNumeric(txtAmount.Text) Then LoanAmount = Convert.ToInt32(txtAmount.Text) Else MsgBox("Invalid amount, please re-enter") txtAmount.Focus() txtAmount.SelectAll() Exit Sub End If ‘ Validate interest rate If IsNumeric(txtRate.Text) Then LoanIRate = 0.01 * Convert.ToDouble(txtRate.Text) / 12 Else MsgBox("Invalid interest rate, please re-enter") txtRate.Focus() txtRate.SelectAll() Exit Sub End If ‘ Validate loan’s duration If IsNumeric(txtDuration.Text) Then LoanDuration = Convert.ToInt32(txtDuration.Text) Else MsgBox("Please specify the loan’s duration as a number of months") txtDuration.Focus() txtDuration.SelectAll() Exit Sub End If ‘ If all data were validated, proceed with calculations Dim payEarly As DueDate If chkPayEarly.Checked Then payEarly = DueDate.BegOfPeriod Else payEarly = DueDate.EndOfPeriod End If Payment = Pmt(LoanIRate, LoanDuration, -LoanAmount, 0, payEarly) txtPayment.Text = Payment.ToString("#.00") End Sub First, we declare three variables in which the loan’s parameters will be stored: LoanAmount , LoanIRate , and LoanDuration. These values will be passed to the Pmt() function as argu- ments. Each text box’s value is examined with an If structure. If the corresponding text box holds a valid number, its value is assigned to the numeric variable. If not, the program dis- plays a warning and exits the subroutine without attempting to calculate the monthly pay- ment. Before exiting the subroutine, however, the code moves the focus to the text box with
142 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING the invalid value and selects the text in the textbox because this is the control that the user will most likely edit. After fixing the incorrect value, the user can click the Show Payment button again. IsNumeric() is another built-in function that accepts a variable and returns True if the variable is a number and False otherwise. You can run the revised application and check it out by entering invalid values in the fields. Notice that you can’t specify an invalid value for the last argument; the CheckBox control won’t let you enter a value. You can only select or clear it, and both options are valid. The actual cal- culation of the monthly payment takes a single line of Visual Basic code. Displaying it requires another line of code. Adding the code to validate the data entered by the user, however, is an entire program. And that’s the way things are.
Well-behaved applications must contain data-validation code. If an application such as Loan- Calculator crashes because of a typing mistake, nothing really bad will happen. The user will try again or else give up on your application and look for a more professional one. However, if the user has been entering data for hours, the situation is far more serious. It’s your responsi- bility as a programmer to make sure that only valid data are used by the application and that the application keeps working, no matter how the user misuses or abuses it. Our sample application is not typical because it calculates the result with a single function call, but in developing typical business applications, you must write a substantial amount of code to validate user input. The reason for validating user input is to control inputs to your code so that you can ensure that it behaves correctly and that you can provide specific error messages to help the user identify the error and correct it. You will notice that the sample applications included in this book don’t contain much data-validation code, because it would obscure the ‘‘useful’’ code that applies to the topic at hand. Instead, they demonstrate specific techniques. You can use parts of the examples in your applications, but you should provide your own data-validation code (and error-handling code, as you’ll see in a moment). Now run the application one last time and enter an enormous loan amount. Try to find out what it would take to pay off the national debt with a reasonable interest rate in, say, 72 months. The program will crash again (as if you didn’t know). This time the program will go down with a different error message, as shown in Figure 4.4. Visual Basic will complain about an overflow. The exact message is Value was either too large or too small for an Int32 , and the pro- gram will stop at the line that assigns the contents of the txtAmount TextBox to the LoanAmount variable. Press the Break button and the offending statement in the code will be highlighted. An overflow is a numeric value too large for the program to handle. This error is usually produced when you divide a number by a very small value. When you attempt to assign a very large value to an Integer variable, you’ll also get an overflow exception. Actually, in the LoanCalculator application, any amount greater than 2,147,483,647 will cause an overflow condition. This is the largest value you can assign to an Integer variable; it’s plenty for our banking needs but not nearly adequate for handling government deficits.
144 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING event handler for this statement? The TextBox control fires the TextChanged event every time its text is changed, and this is the proper place to execute the statement that clears the monthly payment on the form. Because there are three TextBox controls on the form, you must program the TextChanged event of all three controls or write an event handler inside the frmLoan class that handles all three events: Private Sub txtAmount_TextChanged(ByVal (…) Handles txtAmount.TextChanged, txtDuration.TextChanged, txtRate.TextChanged txtPayment.Clear() End Sub Yes, you can write a common handler for multiple events, as long as the events are of the same type and they’re all listed after the Handles keyword. You’ll see another example of the same technique in the following sample project. One of the sample projects for this chapter is a revised version of the LoanCalculator project, the LoanCalculator-Dates project, which uses a different interface. Instead of specifying the duration of the loan in months, this application provides two instances of the DateTimePicker control, which is used to specify dates. Delete the TextBox control and the corresponding Labels and insert two new Label controls and two DateTimePicker controls on the form. Name the DateTimePicker controls dtFrom and dtTo. Users can set the loan’s starting and ending dates on these two controls and the program calculates the duration of the loan in months with the following statement: LoanDuration = DateDiff(DateInterval.Month, dtFrom.Value, dtTo.Value) + 1 The DateDiff() function returns the difference between two dates in the interval supplier as the first argument to the function. The rest of the code doesn’t change; as long as the LoanDuration variable has the correct value, the same statements will produce the correct result. If you open the project, you’ll find a few more interesting statements that set the dtFrom control to the first date of the selected month and the dtTo control to the last date of the selected month.
This next application is more advanced, but it’s not as advanced as it looks. It’s a calculator with a typical visual interface that demonstrates how Visual Basic can simplify the program- ming of fairly advanced operations. If you haven’t tried it, you may think that writing an appli- cation such as this one is way too complicated for a beginner, but it isn’t. The MathCalculator application is shown in Figure 4.5. The application emulates the operation of a handheld calculator and implements basic arith- metic operations. It has the look of a math calculator, and you can easily expand it by adding more features. In fact, adding features such as cosines and logarithms is actually simpler than performing the basic arithmetic operations. This interface will also give you a chance to exercise most of the tools of the IDE for aligning and spacing the controls on a form.
BUILDING A CALCULATOR 145 Figure 4. The calculator applica- tion window Designing the User Interface The application’s interface is straightforward, but it takes a bit of effort. You must align the but- tons on the form and make the calculator look as much like a handheld calculator as possible. Start a new Windows Forms project, the MathCalculator project, and rename the main form from Form1.vb to frmCalculator.vb. Designing the interface of the application isn’t trivial because it’s made up of many buttons, all perfectly aligned on the form. To simplify the design, follow these steps:
will inherit this font. The MathCalculator sample application uses 10-point Verdana font. I’ve used a size of 12 points for the Period button because the 10-point period was too small and very near the bottom of the control.
property to Fixed3D so that it will have a 3D look, as shown in Figure 4.5. Change its ForeColor and BackColor properties too, if you want it to look different from the rest of the form. The sample project uses colors that emulate the — now extinct — green CRT monitors. Name the Label control lblDisplay.
the button carefully so that its caption is centered on the control. The other buttons on the form will be copies of this one, so make sure you’ve designed the first button as best as you can before you start making copies of it. You can also change the button’s style with the FlatStyle property. (You can experiment with the Popup, Standard, and System settings for this property.)
other buttons for the calculator’s digits. Right-click the button and choose Copy from the context menu. The Button control is copied to the Clipboard, and now you can paste it on the form (which is much faster than designing an identical button).
will be pasted on the form. The copy will have the same caption as the button it was copied from, and its name will be Button1.
digit 2. Place the new button to the right of the previous button. You don’t have to align the two buttons perfectly now; later we’ll use the commands of the Format menu to align the buttons on the form. As you move the control around on the form, one or more lines may appear on the design surface at times. These lines are called snap lines , and they appear
BUILDING A CALCULATOR 147 Programming the MathCalculator Now you’re ready to add some code to the application. Double-click one of the digit buttons on the form and you’ll see the following in the code window: Private Sub bttn1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttn1.Click End Sub This is the Click event’s handler for a single digit button. Your first inclination might be to program the Click event handler of each digit button, but repeating the same code 10 times isn’t very productive. (Not to mention that if you decide to edit the code later, the process must be repeated 10 times.) We’re going to use the same event handler for all buttons that represent digits. All you have to do is append the names of the events to be handled by the same sub- routine after the Handles keyword. You should also change the name of the event handler to something that indicates its role. Because this subroutine handles the Click event for all the digit buttons, let’s call it DigitClick(). Here’s the revised declaration of a subroutine that can handle all the digit buttons: Private Sub DigitClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttn0.Click, bttn1.Click, bttn2.Click, bttn3.Click, bttn4.Click, bttn5.Click, bttn6.Click, bttn7.Click, bttn8.Click, bttn9.Click End Sub You don’t have to type all the event names; as soon as you insert the first comma after bttn0.Click, a drop-down list with the names of the controls will open and you can select the name of the next button with the down arrow. Press the spacebar to select the desired control ( bttn1 , bttn2 , and so on), and then type the period. This time, you’ll see another list with the names of the events for the selected control. Locate the Click event and select it by pressing the spacebar. Type the next comma and repeat the process for all the buttons. This extremely convenient feature of the language is IntelliSense: The IDE presents the available and valid keywords as you type. When you press a digit button on a handheld calculator, the corresponding digit is appended to the display. To emulate this behavior, insert the following line in the Click event handler: lblDisplay.Text = lblDisplay.Text + sender.Text This line appends the digit clicked to the calculator’s display. The sender argument of the Click event represents the control that was clicked (the control that fired the event). The Text property of this control is the caption of the button that was clicked. For example, if you have already entered the value 345, clicking the digit 0 displays the value 3450 on the Label control that acts as the calculator’s display. The expression sender.Text is not the best method of accessing the Text property of the button that was clicked, but it will work as long as the Strict option is off. As discussed in
148 CHAPTER 4 GUI DESIGN AND EVENT-DRIVEN PROGRAMMING Chapter 2, we must cast the sender object to a specific type (the Button type) and then call its Text method: CType(sender, Button).Text The code behind the digit buttons needs a few more lines. After certain actions, the display should be cleared. After one of the buttons that correspond to math operations is pressed, the display should be cleared in anticipation of the second operand. Actually, the display must be cleared as soon as the first digit of the second operand is pressed and not as soon as the math operator button is pressed. Likewise, the display should also be cleared after the user clicks the Equals button. Revise the DigitClick event handler, as shown in Listing 4.3. Listing 4.3: The DigitClick event Private Sub DigitClick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttn1.Click, bttn2.Click, bttn3.Click, bttn4.Click, bttn5.Click, bttn6.Click, bttn7.Click, bttn8.Click, bttn9.Click If clearDisplay Then lblDisplay.Text = "" clearDisplay = False End If lblDisplay.Text = lblDisplay.Text + sender.text End Sub The clearDisplay variable is declared as Boolean, which means it can take a True or False value. Suppose the user has performed an operation and the result is on the calculator’s dis- play. The user now starts typing another number. Without the If clause, the program would continue to append digits to the number already on the display. This is not how calculators work. When the user starts entering a new number, the display must be cleared. Our program uses the clearDisplay variable to know when to clear the display. The Equals button sets the clearDisplay variable to True to indicate that the display con- tains the result of an operation. The DigitClick() subroutine examines the value of this vari- able each time a new digit button is pressed. If the value is True, DigitClick() clears the display and then prints the new digit on it. The subroutine also sets clearDisplay to False so that when the next digit is pressed, the program won’t clear the display again. What if the user makes a mistake and wants to undo an entry? The typical handheld calcula- tor has no Backspace key. The Clear key erases the current number on the display. Let’s imple- ment this feature. Double-click the C button and enter the code of Listing 4.4 in its Click event. Listing 4.4: Programming the Clear button Private Sub bttnClear_Click (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles bttnClear.Click lblDisplay.Text = "" End Sub