Logo: TechTrax...brought to you by MouseTrax Computing Solutions

Excel VBA: No Experience Necessary - Lesson 4

by Mark Thorpe

Back again, for Lesson 4. In last month’s Lesson 3 we learned about writing our own Excel functions, as well as how to incorporate Excel built-in functions in our VBA code. This month, we will cover the exciting topic of creating your own forms! But first, of course, we will start with…

Solution to Last Month’s Exercise
Last month I closed with an exercise for you to try which involved writing two functions: DayOfYear, which represents which day of the year, in integer form, a date represents, and ZodiacSign, which returns the zodiac sign for a particular date. You may download the complete solution here: Excel VBA Article 3 Example Solution.xls (in zipped format).

Let’s start with the function declaration for DayOfYear. The function will need to take a Date as a parameter, and return an integer:

Public Function DayOfYear(SomeDate As Date) As Integer

To calculate the day of the year, we’ll first determine the month and day of SomeDate using the VBA date functions Month() and Day(). In this case, Day represents the day of the month, not the day of the year.

Example 1a.

Public Function DayOfYear(SomeDate As Date) As Integer

Dim iMonth As Integer
Dim iDay As Integer
iMonth = Month(SomeDate)
iDay = Day(SomeDate)

We’ll start at zero, and add the appropriate number of days for each month which precedes our date. Then we add the number of days into the current month (i.e. the day of the month)...

Example 1b.

Public Function DayOfYear(SomeDate As Date) As Integer

Dim iMonth As Integer
Dim iDay As Integer
iMonth = Month(SomeDate)
iDay = Day(SomeDate)

DayOfYear = 0
If iMonth > 1 Then
    DayOfYear = DayOfYear + 31
End If
If iMonth > 2 Then
    DayOfYear = DayOfYear + 28
End If
If iMonth > 3 Then
    DayOfYear = DayOfYear + 31
End If

...

If iMonth > 11 Then
    DayOfYear = DayOfYear + 30
End If

' Add number of days into the current month:
DayOfYear = DayOfYear + iDay

End Function

For the sake of brevity, I left out months 4 through 10, but you get the picture. The last thing we need to do is account for the possibility that our date occurs in a leap year. To do this we will use the Year() function, and the Mod operator, which calculates the remainder of one number divided by another. I won’t insult your intelligence by explaining that a leap year is a multiple of four, so when divided by four, the remainer is zero. We will put this if statement inside our if iMonth > 2 clause.

Example 1c.

If iMonth > 2 Then
   DayOfYear = DayOfYear + 28
   ' Add one extra day if this is a leap year:
   If Year(SomeDate) Mod 4 = 0 Then
      DayOfYear = DayOfYear + 1
   End If
End If

I gave a hint last month that you would be using a series of elseif statements, and it certainly can be done that way, but upon further review I decided that using separate if statements, one for each month, would be the "cleaner", if longer, way to implement this function. If you’re interested in seeing an alternative implementation which uses elseif, see function DayOfYear_Alt1 in the solution download (see above). An even shorter way which involves calling another user-defined function, DaysInMonth, is presented in function DayOfYear_Alt2.

For the function ZodiacSign, we will use elseif statements, simply figuring out, based on the day of the year, which sign represents that day. We also have to adjust back one day for leap years…

Example 1d.

Public Function ZodiacSign(BirthDate As Date) As String

Dim iDayofYear As Integer

iDayofYear = DayOfYear(BirthDate)

' Adjust back one day if a leap year, and later than Feb 28...
If Year(BirthDate) Mod 4 = 0 And iDayofYear > 59 Then
   iDayofYear = iDayofYear - 1
End If

If iDayofYear < 20 Then
   ZodiacSign = "Capricorn"
ElseIf iDayofYear < 50 Then
   ZodiacSign = "Aquarius"
ElseIf iDayofYear < 81 Then
   ZodiacSign = "Pisces"
ElseIf iDayofYear < 111 Then
   ZodiacSign = "Aries"
ElseIf iDayofYear < 142 Then
   ZodiacSign = "Taurus"
ElseIf iDayofYear < 173 Then
   ZodiacSign = "Gemini"
ElseIf iDayofYear < 205 Then
   ZodiacSign = "Cancer"
ElseIf iDayofYear < 236 Then
   ZodiacSign = "Leo"
ElseIf iDayofYear < 267 Then
   ZodiacSign = "Virgo"
ElseIf iDayofYear < 297 Then
   ZodiacSign = "Libra"
ElseIf iDayofYear < 327 Then
   ZodiacSign = "Scorpio"
ElseIf iDayofYear < 357 Then
   ZodiacSign = "Sagittarius"
Else
   ZodiacSign = "Capricorn"
End If

End Function

Creating Your Own Forms
If you want to spruce up your humble Excel spreadsheet with a handsome user interface, creating your own “UserForms” is the only way to go. Keep in mind that I am a programmer by trade. This means that while I can teach you how to create user interface, I am unable, by definition, to design good user interface.

To create a form, bring up the Visual Basic Editor from Excel. Select Insert, UserForm from the main menu. You will be presented with a blank form with a caption of “UserForm1”. Your form, and each of the controls you will place on it, has a set of properties which determine how it will look and behave. To view these properties, click on menu item View, Properties Window (or type F4). The left column lists each property, and the right column lists the value of each property, which you may change. The first property listed is (Name). You will use the Name property in the code which will bring up your form. Try changing the Caption property, and toying with some of the other properties. You can also resize your form using the border, and small boxes, which appear around its outside edge. (Note that the tree structure on the left, in the Project Explorer window, now has a folder called “Forms” and that your UserForm1 appears beneath it.)

Next, let’s drop a few controls on our form. You will do this using the controls “Toolbox”. Click on menu item View, Toolbox. (If it is greyed out, try clicking on your user form first. Toolbox is disabled when focus is in the Properties window.)

Click on the capital A button to create a Label control. A label is simply text that appears on your form. Click and drag a box on your form. The Properties window now shows you the properties of your first control, named Label1. In the Caption property, type “Enter Some Data Here…” or something slightly more clever.

Below your label, add a TextBox control by clicking on the lowercase “ab” button in the toolbox. Change the (Name) property of the TextBox to “txtData”. Next add two CommandButton controls (small 3-D rectangle button on the right side of the Toolbox). For the first button, change the Name property to “cmdAdd” and the Caption property to “Add”. For the second, change the name to “cmdClose” and the caption to “Close”.

You should now have a form which looks something like this…

Invoking Your Form
Just as each of the Excel objects (see Lesson 2) has both properties and methods, so does your UserForm, and each of its controls. You can think of them as additional types of Excel object. We’ve already seen the properties of each in the Properties window in the Visual Basic Editor. Generally, you won’t use many UserForm or control methods, but UserForm has a method without which you would not be able to Show your form. It’s called… Show.

To bring up our sample form, we’ll try something else new… adding a control directly to our spreadsheet. Back in Excel itself, click on View, Toolbars, Control Toolbox. This Toolbox is quite similar to the Toolbox in the VB Editor. Click on the button for the CommandButton control (3-D rectangle), then place it on your spreadsheet by clicking and dragging. Like the buttons you drew on your form, this button also has properties. To view them, click the button in the upper right of the Toolbox, the hand holding a card (or is that an electic bill?). Change the name to “cmdShowForm”, and the caption to “Show My Form”. Next, double-click on the button. This will switch you back to the VB Editor and automatically create an empty subroutine called cmdShowForm_Click within your Sheet1 worksheet object. As you may guess, this is the subroutine which will be called when the user clicks the button. Within this subroutine, enter a single line of code:

Example 2.

Private Sub cmdShowForm_Click()
   UserForm1.Show
End Sub

Next, switch back to Excel and click on the Design Mode button, in the upper-left corner of the Control Toolbox. This is the button which appears to be someone stabbing a shark with a very stubby pencil. Not a good idea. Next click on your “Show My Form” button and… voila! There’s your user form. You’ll notice that while you can type information into the textbox, neither of your buttons actually does anything when you click on them. That’s next. For now, close your form by clicking the X button in the upper right.

Writing Code for a User Form
In the Visual Basic Editor, bring up UserForm1. Double-click on the Close button. Just as when we double-clicked on the “Show My Form” button in the spreadsheet, double-clicking the Close button automatically creates a subroutine called cmdClose_Click, which will be called when the user clicks the Close button. The VBA command to close a form is Unload. Therefore we could close our form with the line of code “Unload UserForm1”. However, since this code is UserForm1’s own code, we can instead type “Unload Me”. “Me” is a VBA keyword that a form can use to refer to itself.

Example 3.

Private Sub cmdClose_Click()
   Unload Me
End Sub

That was the easy one. Next, let’s switch back to the form. I mentioned above that the form appears under a “Forms” folder in the Project Explorer window on the left. To view the form, you can double-click on its name in the Project Explorer, or highlight it and click menu item View, Object (keyboard shortcut Shift+F7). To view the code for a form, highlight it and click menu item View, Code (keyboard shortcut F7.

Double-click the Add button to create the cmdAdd_Click subroutine. The first thing we will do with this button is, when the user clicks it, read the contents of the TextBox and display it in a message box. The contents of a VBA TextBox control is accessible by using the Text property. We will declare a string variable called sData, set it equal to the Text property of the TextBox, then display it in a message box:

Example 4.

Private Sub cmdAdd_Click()
   Dim sData As String
   sData = txtData.Text
   MsgBox sData
End Sub

Give it a try. Switch back to Excel, click “Show My Form”, enter some text, then click “Add”. Try your Close button too.

Next let’s add the data to the spreadsheet instead of showing it in a message box. We already know how to set the value of a worksheet cell. The only question is where to put it. For this example, we will add each piece of “data” to the end of a list in column A. We’ll declare a variable called lRowNum, determine how many rows are already used (with ActiveSheet.UsedRange.Rows.Count), then set lRowNum to the next row. One quirk of Excel will throw a small monkey wrench into this plan. Even if the spreadsheet is completely empty, ActiveSheet.UsedRange.Rows.Count will be set to 1. To get around this, we will first check to see if cell A1 is empty. If so, we will put the data there. If not, count the used rows:

Example 4.

Private Sub cmdAdd_Click()

Dim sData As String
Dim lRowNum As Long

sData = txtData.Text
' Put the data in the current worksheet:
If Cells(1, 1).Value = "" Then
   lRowNum = 1
Else
   lRowNum = ActiveSheet.UsedRange.Rows.Count + 1
End If
Cells(lRowNum, 1).Value = sData

End Sub

Try it again. You’ll notice two small problems. After we add the text to the spreadsheet, it remains in the TextBox. Also, the focus is now on the Add button. This means that to make another entry, we have to first click on (or tab back to) the TextBox, then we have to erase the previous entry before we can make a new one. These problems are solved easily. Just as we can use the Text property of the TextBox to read its contents, we can use it to set the contents. Also, each control you place on your form has a method called SetFocus. Add two lines of code to your subroutine and try it again:

Private Sub cmdAdd_Click()
   Dim sData As String
   Dim lRowNum As Long

   sData = txtData.Text
   ' Put the data in the current worksheet:
   If Cells(1, 1).Value = "" Then
      lRowNum = 1
   Else
      lRowNum = ActiveSheet.UsedRange.Rows.Count + 1
   End If
   Cells(lRowNum, 1).Value = sData
   ' Clear text box and set focus for next entry:
   txtData.Text = ""
   txtData.SetFocus

End Sub

Much better!

Well, I hate to cut this short, but I’m going on vacation this week! You’ve had but a taste of user forms in Excel. If you’d like an exercise to practice with, try making a phone list form for yourself. Store names in column A, and phone numbers in column B. This will be similar to the exercise we’ve just done, but in addition to adding new phone numbers, your form should allow you to go up and down your list to view existing numbers, change existing entries, and delete entries. Your form should have one TextBox for name and another for telephone number. It should have Previous, Next, Add, Delete, and Close buttons. Couple of hints:

You can write code which will be called as soon as your form comes up, by creating a subroutine called: UserForm_Activate. This is used to set the initial contents of the form. For example, if we wanted the form we created above to initially display the first string in our list, we would add:

Private Sub UserForm_Activate()
   txtData.Text = ActiveSheet.Cells(1, 1).Value
End Sub

You will need to keep track of which row number the form is currently displaying. The easiest way to do this will be to declare a variable within the code of your form, but not within any of its subroutines. At the top of the code window for your form, add the line:

Dim lCurrentRow As Long

You can then use this variable in any of your subroutines. You will want to set it to 1 in your UserForm_Activate subroutine, then change its value accordingly each time the user clicks Previous or Next.

Your Add button will not work quite the same as the one we created in the example above. Instead, your Add button should set lCurrentRow to the first unused row in your spreadsheet, and clear both TextBox controls. You will then save whatever the user has entered to the spreadsheet when the user clicks either Previous, Next, or Close.

If you want a bit more of a challenge, try adding a dropdown list box (“ComboBox” control) to your form, and filling it with all existing names. When the user selects an item from the list, set the TextBox controls to the selected person’s name and telephone number. You can also try adding more TextBox controls to your form to turn the phone list into an address book.

I’ve attached the example we did above, for your enjoyment: Excel VBA Lesson 4 Example.xls. Until we meet again…


Need further help getting your Excel VBA code right? Join our free Excel VBA support group! See this link for details: http://groups.yahoo.com/group/ExcelVBA/ .

Click to rate this article.

 

Go up to the top of this page.
This site powered by the Logical Web Publisher™: Content management by Logical Expressions, Inc.