Chapter 15 EVENT- DRIVEN
PROGRAMMING

How do you disable a built-in shortcut menu when a user clicks on a worksheet cell? How do you display a custom message before a workbook is opened or closed? How can you validate data entered in a cell or range of cells?

To gain complete control over Microsoft Excel, you must learn how to respond to events. Learning how to program events will allow you to implement your own functionality in an Excel application. The first thing you need to know about this subject is what an event is. An event is an action recognized by an object. An event is something that happens to objects that are part of Microsoft Excel. Once you learn about events in Excel, you will find it easier to understand events that occur to objects in Word or any other Microsoft Office application.

Events can be triggered by an application user (such as you), another program, or the system itself. So, how can you trigger an event? Suppose you right-clicked a worksheet cell. This particular action would display a built-in shortcut menu for a worksheet cell, allowing you to quickly access the most frequently used commands related to worksheet cells. But what if this particular built-in response isn’t appropriate under certain conditions? You may want to entirely disallow right-clicking in a worksheet or perhaps ensure that a custom menu appears on a cell shortcut menu when the user right-clicks any cell. The good news is you can use VBA to write code that can react to events as they occur. The following Microsoft Excel objects can respond to events:

Worksheet

Chart sheet

Query table

Workbook

Application

You can decide what should happen when a particular event occurs by writing an event procedure.

INTRODUCTION TO EVENT PROCEDURES

A special type of VBA procedure, an event procedure, is used to react to specific events. This procedure contains VBA code that handles a particular event. Some events may require a single line of code, while others can be more complex. Event procedures have names, which are created in the following way:

ObjectName_EventName()

In the parentheses after the name of the event, you can place parameters that need to be sent to the procedure. The programmer cannot change the name of the event procedure.

Before you can write an event procedure to react to an Excel event, you need to know:

The names of the particular object and event to which you want to respond.

Figure 15.1 illustrates how objects that respond to events display a list of events in the Procedure drop-down list in the Code window. Also, you can use the Object Browser to find out the names of the events, as shown in Figure 15.2.

The place where you should put the event code.

Some events are coded in a standard module; others are stored in a class module. While workbook, chart sheet, and worksheet events are available for any open sheet or workbook, to create event procedures for an embedded chart, query table, or the Application object, you must first create a new object using the With Events keywords in the class module.

FIGURE 15.1. You can find out the event names in the Code window.

FIGURE 15.2. You can also find out the event names in the Object Browser.

WRITING YOUR FIRST EVENT PROCEDURE

At times you will want to trigger a certain operation when a user invokes an Excel command. For example, when the user attempts to save a workbook you may want to present him with the opportunity to copy the active worksheet to another workbook. Your first event procedure in this chapter explores this scenario. Once this event procedure is written, its code will run automatically when a user attempts to save the workbook file in which the procedure is located.

Please note files for the “Hands-On” project may be found on the companion CD-ROM.

Hands-On 15.1. Writing an Event Procedure

1. Open a new workbook and save it as C:\VBAExcel2016_ByExample\Chap15_VBAExcel2016.xlsm.

2. Change the name of Sheet1 in the Chap15_VBAExcel2016.xlsm workbook to Test.

3. Type anything in cell A1 and press Enter.

4. Switch to the Visual Basic Editor screen.

5. In the Project Explorer, double-click ThisWorkbook in the Microsoft Excel Objects folder under VBAProject (Chap15_VBAExcel2016.xlsm).

6. In the ThisWorkbook Code window, enter the following Workbook_BeforeSave event procedure:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

If MsgBox("Would you like to copy " & vbCrLf & "this worksheet to " & vbCrLf & "a new workbook?", vbQuestion + vbYesNo) = vbYes Then

Sheets(ActiveSheet.Name).Copy

End If

End Sub

The above event procedure uses a MsgBox function to display a two-button dialog box asking the user whether the current worksheet should be copied to another workbook. If the user clicks the Yes button, Visual Basic will open a new workbook and copy the active worksheet to it. The original workbook file will not be saved. If, however, the user clicks No, the Excel built-in save event will be triggered. If the workbook has never been saved before, you will be presented with the Save As dialog box where you can specify the filename, the file format, and its location.

7. Switch to the Microsoft Excel application window, click the File tab, and choose Save.

The Workbook_BeforeSave event procedure that you wrote in Step 6 will be triggered at this time. Click Yes to the message box. Excel will open a new workbook with the copy of the current worksheet.

8. Close the workbook file created by Excel without saving any changes. Do not close the Chap15_VBAExcel2016.xlsm workbook.

9. Click the File tab and choose Save to save Chap15_VBAExcel2016.xlsm.

Notice that again you are prompted with the dialog box. Click No to the message. Notice that the workbook file is now being saved.

But what if you wanted to copy the worksheet file to another workbook and also save the original workbook file? Let’s modify our Workbook_BeforeSave procedure to make sure the workbook file is saved regardless of whether the user answered Yes or No to the message.

10. Change the Workbook_BeforeSave procedure as follows:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

Dim wkb As Workbook

Set wkb = ActiveWorkbook

Cancel = False

If MsgBox("Would you like to copy " & vbCrLf & "this worksheet to " & vbCrLf & "a new workbook?", vbQuestion + vbYesNo) = vbYes Then

Sheets(ActiveSheet.Name).Copy

wkb.Activate

End If

End Sub

To continue with the saving process, you need to set the Cancel argument to False. This will trigger the Excel built-in save event. Because copying will move the focus to the new workbook that does not contain the customized Workbook_BeforeSave procedure, you need to activate the original workbook after performing the copy. We can get back pretty easily to the original workbook by setting a reference to it at the beginning of the event procedure and then issuing the wkb.Activate statement.

 

NOTE

If you’d rather call your own saving procedure, set the Cancel property to True and type the name of your custom save procedure. Here’s a short event procedure example:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

' abort the built-in save event

Cancel = True

' call your own saving procedure

MyCustomSaveProcedure

End Sub

11. Type anything in the Test worksheet in the Chap15_VBAExcel2016.xlsm file, then click the Save button on the Quick Access toolbar.

When you click Yes or No in response to the message box, Excel proceeds to save the workbook file (you should see the flashing message in the status bar). If you clicked Yes, Excel also copies the Test worksheet to another workbook. After all these tasks are completed, Excel activates the Chap15_VBAExcel2016.xlsm workbook.

12. If you answered Yes in the previous step, close the workbook file created by Excel without saving any changes. Do not close Chap15_VBAExcel2016.xlsm.

Now that you know how to use the Cancel argument, let’s look at the other argument of the Workbook_BeforeSave event—SaveAsUI. This argument allows you to handle the situation when the user chooses the Save As option. Suppose that in our procedure example we want to prompt the user to copy the current worksheet to another workbook only when the Save option is selected. In cases when the file has not yet been saved or the user wants to save the workbook with a different filename, the default Save As dialog box will pop up and the user will not be bothered with the copy prompt. The following step takes this situation into consideration.

13. Modify the Workbook_BeforeSave event procedure as follows:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

If SaveAsUI = True Then Exit Sub

Dim wkb As Workbook

Set wkb = ActiveWorkbook

Cancel = False

If MsgBox("Would you like to copy " & vbCrLf & "this worksheet to " & vbCrLf & "a new workbook?", vbQuestion + vbYesNo) = vbYes Then

Sheets(ActiveSheet.Name).Copy

wkb.Activate

End If

End Sub

14. Switch to the Chap15_VBAExcel2016 application window, click the File tab, and choose Save As | Excel Macro-Enabled Workbook.

Notice that you are not prompted to copy the current worksheet to another workbook. Instead, Excel proceeds to run its own built-in Save As process. When the Save As dialog box appears, click Cancel.

ENABLING AND DISABLING EVENTS

You can use the Application object’s EnableEvents property to enable or disable events. If you are writing a VBA procedure and don’t want a particular event to occur, set the EnableEvents property to False.

To demonstrate how you can prevent a custom event procedure from running, we will write a procedure in a standard module that will save the workbook after making some changes in the active sheet. We will continue working with the Chap15_VBAExcel2016 file because it already contains the Worksheet_BeforeSave event procedure we want to block in this demonstration.

Hands-On 15.2. Disabling a Custom Event Procedure

This Hands-On requires prior completion of Hands-On 15.1.

1. Choose Insert | Module to add a standard module to VBAProject (Chap15_VBAExcel2016.xlsm) and rename it StandardProcedures.

2. In the module’s Code window, enter the following EnterData procedure:

Sub EnterData()

With ActiveSheet.Range("A1:B1")

.Font.Color = vbRed

.Value = 15

End With

Application.EnableEvents = False

ActiveWorkbook.Save

Application.EnableEvents = True

End Sub

Notice that prior to calling the Save method of the ActiveWorkbook property, we have disabled events by setting the EnableEvents property to False. This will prevent the Workbook_BeforeSave event procedure from running when Visual Basic encounters the statement to save the workbook. We don’t want the user to be prompted to copy the worksheet while running the EnterData procedure. When Visual Basic has completed the saving process, we want the system to respond to the events as we programmed them, so we enable the events with the Application.EnableEvents statement set to True.

3. Switch to the Chap15_VBAExcel2016.xlsm application window and choose View | Macros | View Macros. In the Macro dialog box, select EnterData and click Run.

Notice that when you run the EnterData procedure, you are not prompted to copy the worksheet before saving. This indicates that the code you entered in the Hands-On 15.1 Workbook_BeforeSave event procedure is not running.

4. Close the Chap15_VBAExcel2016 workbook.

EVENT SEQUENCES

Events occur in response to specific actions. Events also occur in a predefined sequence. Table 15.1 demonstrates the sequence of events that occur while opening a new workbook, adding a new worksheet to a workbook, and closing the workbook.

TABLE 15.1. Event sequences

Action

Object

Event Sequence

Opening a new workbook

Workbook

NewWorkbook

WindowDeactivate

WorkbookDeactivate

WorkbookActivate

WindowActivate

Inserting a new sheet into a workbook

Workbook

WorkbookNewSheet

SheetDeactivate

SheetActivate

Closing a workbook

Workbook

WorkbookBeforeClose

WindowDeactivate

WorkbookDeactivate

WorkbookActivate

WindowActivate

WORKSHEET EVENTS

A Worksheet object responds to such events as activating and deactivating a worksheet, calculating data in a worksheet, making a change to a worksheet, and double-clicking or right-clicking a worksheet. Table 15.2 lists some of the events to which the Worksheet object can respond.

TABLE 15.2. Worksheet events (a partial listing)

Worksheet Event Name

Event Description

Activate

This event occurs upon activating a worksheet.

Deactivate

This event occurs when the user activates a different sheet.

SelectionChange

This event occurs when the user selects a worksheet cell.

Change

This event occurs when the user changes a cell formula.

Calculate

This event occurs when the user recalculates the worksheet.

BeforeDoubleClick

This event occurs when the user double-clicks a worksheet cell.

BeforeRightClick

This event occurs when the user right-clicks a worksheet cell.

Let’s try out these events to get the hang of them.

Worksheet_Activate()

This event occurs upon activating a worksheet.

Hands-On 15.3. Writing the Worksheet_Activate() Event Procedure

1. Open a new workbook and save it as Chap15_WorksheetEvents.xlsm in your VBAExcel2016_ByExample folder.

2. Insert a new worksheet to the current workbook.

3. Switch to the Visual Basic Editor window.

4. In the Project Explorer window, double-click Sheet2 under VBAProject (Chap15_WorksheetEvents.xlsm) in the Microsoft Excel Objects folder.

5. In the Sheet2 Code window, enter the code shown below:

Dim shtName As String

Private Sub Worksheet_Activate()

shtName = ActiveSheet.Name

Range("B2").Select

End Sub

The example procedure selects cell B2 each time the sheet is activated. Notice that the shtName variable is declared at the top of the module.

6. Switch to the Microsoft Excel application window and activate Sheet2.

Notice that when Sheet2 is activated, the selection is moved to cell B2. Excel also stores the sheet name in the shtName variable that was declared at the top of the module. We will need this value as we work with other event procedures in this section.

Worksheet_Deactivate()

This event occurs when the user activates a different sheet in a workbook.

Hands-On 15.4. Writing the Worksheet_Deactivate() Event Procedure

This Hands-On exercise uses the Chap15_WorksheetEvents workbook created in Hands-On 15.3.

1. Switch to the Visual Basic Editor window. In the Sheet2 Code window, enter the Worksheet_Deactivate procedure as shown below:

Private Sub Worksheet_Deactivate()

MsgBox "You deactivated " & shtName & "." & vbCrLf & "You switched to " & ActiveSheet.Name & "."

End Sub

The example procedure displays a message when Sheet2 is deactivated.

2. Switch to the Microsoft Excel application window and click the Sheet2 tab.

The Worksheet_Activate procedure that you created in Hands-On 15.3 will run first. Excel will select cell B2 and store the name of the worksheet in the shtName global variable declared at the top of the Sheet2 code module.

3. Now click any other sheet in the active workbook.

Notice that Excel displays the name of the worksheet that you deactivated and the name of the worksheet you switched to.

Worksheet_SelectionChange()

This event occurs when the user selects a worksheet cell.

Hands-On 15.5. Writing the Worksheet_SelectionChange() Event Procedure

1. In the current workbook, insert a new worksheet.

2. Switch to the Visual Basic Editor window. In the Project Explorer window, double-click Sheet3 under VBAProject (Chap15_WorksheetEvents.xlsm) in the Microsoft Excel Objects folder.

3. In the Sheet3 Code window, enter the Worksheet_SelectionChange procedure as shown below:

Private Sub Worksheet_SelectionChange(ByVal Target As Excel.Range)

Dim myRange As Range

On Error Resume Next

Set myRange = Intersect(Range("A1:A10"), Target)

If Not myRange Is Nothing Then

MsgBox "Data entry or edits are not permitted."

End If

End Sub

The example procedure displays a message if the user selects any cell in myRange.

4. Switch to the Microsoft Excel application window and activate Sheet3. Click on any cell within the specified range A1:A10.

Notice that Excel displays a message whenever you click a cell in the restricted area.

Worksheet_Change()

This event occurs when the user changes a cell formula.

Hands-On 15.6. Writing the Worksheet_Change() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click Sheet1 in the Microsoft Excel Objects folder of Chap15_WorksheetEvents.xlsm.

2. In the Sheet1 Code window, enter the Worksheet_Change event procedure as shown below:

Private Sub Worksheet_Change(ByVal Target As Excel.Range)

Application.EnableEvents = False

Target = UCase(Target)

Columns(Target.Column).AutoFit

Application.EnableEvents = True

End Sub

The example procedure changes what you type in a cell to uppercase. The column where the target cell is located is then autosized.

3. Switch to the Microsoft Excel application window and activate Sheet1. Enter any text in any cell.

Notice that as soon as you press the Enter key, Excel changes the text you typed to uppercase and autosizes the column.

Worksheet_Calculate()

This event occurs when the user recalculates the worksheet.

Hands-On 15.7. Writing the Worksheet_Calculate() Event Procedure

1. Add a new sheet to the Chap15_WorksheetEvents workbook. In cell A2 of this newly added sheet, enter 1, and in cell B2, enter 2. Enter the following formula in cell C2: = A2+B2.

2. Switch to the Visual Basic Editor window, activate the Project Explorer window, and double-click the sheet you added in Step 1.

3. In the Code window, enter the code of the Worksheet_Calculate procedure as shown below:

Private Sub Worksheet_Calculate()

MsgBox "The worksheet was recalculated."

End Sub

4. Switch to the Microsoft Excel application window and modify the entry in cell B2 on the sheet you added in Step 1 by typing any number.

Notice that after leaving Edit mode, the Worksheet_Calculate event procedure is triggered and you are presented with a custom message.

Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

This event occurs when the user double-clicks a worksheet.

Hands-On 15.8. Writing the Worksheet_BeforeDoubleClick() Event Procedure

1. Enter any data in cell C9 on Sheet2 of the Chap15_WorksheetEvents workbook.

2. In the Visual Basic Editor window, activate the Project Explorer window and open the Microsoft Excel Objects folder. Double-click Sheet2.

3. In the Sheet2 Code window, type the code of the procedure as shown below:

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)

If Target.Address = "$C$9" Then

MsgBox "No double-clicking, please."

Cancel = True

Else

MsgBox "You may edit this cell."

End If

End Sub

The example procedure disallows in-cell editing when cell C9 is double-clicked.

4. Switch to the Microsoft Excel application window and double-click cell C9 on Sheet2.

The Worksheet_BeforeDoubleClick event procedure cancels the built-in Excel behavior, and the user is not allowed to edit the data inside the cell. However, the user can get around this restriction by clicking on the formula bar or pressing F2. When writing event procedures that restrict access to certain program features, write additional code that prevents any workaround.

Worksheet_BeforeRightClick (ByVal Target As Range, Cancel As Boolean)

This event occurs when the user right-clicks a worksheet cell.

Hands-On 15.9. Writing the Worksheet_BeforeRightClick() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click Sheet2 in the Microsoft Excel Objects folder.

2. In the Sheet2 Code window, enter the code of the Worksheet_BeforeRightClick procedure as shown below:

Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean)

With Application.CommandBars("Cell")

.Reset

If Target.Rows.Count > 1 Or Target.Columns.Count > 1 Then

With .Controls.Add(Type:=msoControlButton, before:=1, temporary:=True)

.Caption = "Print…"

.OnAction = "PrintMe"

End With

End If

End With

End Sub

The example procedure adds a Print option to the cell shortcut menu when the user selects more than one cell on the worksheet.

3. Insert a new module into the current project and enter the PrintMe procedure as shown below:

Sub PrintMe()

Application.Dialogs(xlDialogPrint).Show arg12:=1

End Sub

The PrintMe procedure is called by the Worksheet_BeforeRightClick event when the user selects the Print option from the shortcut menu. Notice that the Show method of the Dialogs collection is followed by a named argument: arg12:=1. This argument will display the Print dialog box with the preselected option button “Selection” in the Print area of the dialog box. Excel dialog boxes are covered in the next chapter.

4. Switch to the Microsoft Excel application window and right-click on any single cell in Sheet2.

Notice that the shortcut menu appears with the default options.

5. Now select at least two cells in the Sheet2 worksheet and right-click the selected area.

You should see the Print option as the first menu entry. Click the Print option and notice that instead of the default “Print active sheet,” the Print dialog displays “Print Selection.”

6. Save and close the Chap15_WorksheetEvents.xlsm workbook file.

 

NOTE

The Worksheet_BeforeRightClick event procedure relies on the CommandBar object to customize Excel’s built-in context menu. Before Excel 2010, the CommandBar object was the only way to create, modify, or disable context menus. Excel 2016 still supports CommandBars for compatibility; however, you should rely on the RibbonX model (as discussed in Chapter 19) to add your own customizations to context menus.

WORKBOOK EVENTS

Workbook object events occur when the user performs such tasks as opening, activating, deactivating, printing, saving, and closing a workbook. Workbook events are not created in a standard VBA module. To write code that responds to a particular workbook you can:

Double-click the ThisWorkbook object in the Visual Basic Editor’s Project Explorer.

In the Code window that appears, open the Object drop-down list on the left-hand side and select the Workbook object.

In the Procedure drop-down list (the one on the right), select the event you want. The selected event procedure stub will appear in the Code window as shown below:

Private Sub Workbook_Open()

place your event handling code here

End Sub

Table 15.3 lists some of the events to which the Workbook object can respond.

TABLE 15.3. Workbook events (a partial listing)

Workbook Event Name

Event Description

Activate

This event occurs when the user activates the workbook. This event will not occur when the user activates the workbook by switching from another application.

Deactivate

This event occurs when the user activates a different workbook within Excel. This event does not occur when the user switches to a different application.

Open

This event occurs when the user opens a workbook.

BeforeSave

This event occurs before the workbook is saved. The SaveAsUI argument is read-only and refers to the Save As dialog box. If the workbook has not been saved, the value of SaveAsUI is True; otherwise, it is False.

BeforePrint

This event occurs before the workbook is printed and before the Print dialog appears. The example procedure places the full workbook’s name in the document footer prior to printing if the user clicks Yes in the message box.

BeforeClose

This event occurs before the workbook is closed and before the user is asked to save changes.

NewSheet

This event occurs after the user creates a new sheet in a workbook.

WindowActivate

This event occurs when the user shifts the focus to any window showing the workbook.

WindowDeactivate

This event occurs when the user shifts the focus away from any window showing the workbook.

WindowResize

This event occurs when the user opens, resizes, maximizes, or minimizes any window showing the workbook.

Let’s try out the above events to get the hang of them.

Workbook_Activate()

This event occurs when the user activates the workbook. This event will not occur when the user activates the workbook by switching from another application.

Hands-On 15.10. Writing the Workbook_Activate() Event Procedure

1. Open a new workbook and save it as Chap15_WorkbookEvents.xlsm in your C:\VBAExcel2016__ByExample folder.

2. Switch to the Visual Basic Editor window. In the Project Explorer window, double-click ThisWorkbook in the Microsoft Excel Objects folder.

3. In the ThisWorkbook Code window, type the Workbook_Activate procedure as shown below:

Private Sub Workbook_Activate()

MsgBox "This workbook contains " & ThisWorkbook.Sheets.Count & " sheets."

End Sub

The example procedure displays the total number of worksheets when the user activates the workbook containing the Workbook_Activate event procedure.

4. Switch to the Microsoft Excel application window and open a new workbook.

5. Activate the Chap15_WorkbookEvents workbook. Excel should display the total number of sheets in this workbook.

Workbook_Deactivate()

This event occurs when the user activates a different workbook within Excel. This event does not occur when the user switches to a different application.

Hands-On 15.11. Writing the Workbook_Deactivate() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click ThisWorkbook in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents.xlsm).

2. In the ThisWorkbook Code window, type the Workbook_Deactivate procedure as shown below:

Private Sub Workbook_Deactivate()

Dim cell As Range

For Each cell In ActiveSheet.UsedRange

If Not IsEmpty(cell) Then

Debug.Print cell.Address & ":" & cell.Value

End If

Next

End Sub

The example procedure will print to the Immediate window the addresses and values of cells containing entries in the current workbook when the user activates a different workbook.

3. Switch to the Microsoft Excel application window and make some entries on the active sheet. Next, activate a different workbook.

This action will trigger the Workbook_Deactivate event procedure.

4. Switch to the Visual Basic Editor screen and open the Immediate window to see what entries were reported.

Workbook_Open()

This event occurs when the user opens a workbook.

Hands-On 15.12. Writing the Workbook_Open() Event Procedure

1. Double-click the ThisWorkbook object in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents.xlsm).

2. In the ThisWorkbook Code window, type the Workbook_Open procedure as shown below:

Private Sub Workbook_Open()

ActiveSheet.Range("A1").Value = Format(Now(), "mm/dd/yyyy")

Columns("A").AutoFit

End Sub

The example procedure places the current date in cell A1 when the workbook is opened.

3. Save and close Chap15_WorkbookEvents.xlsm and then reopen it.

When you open the workbook file again, the Workbook_Open event procedure will be triggered and the current date will be placed in cell A1 on the active sheet.

Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

This event occurs before the workbook is saved. The SaveAsUI argument is read-only and refers to the Save As dialog box. If the workbook has not been saved, the value of SaveAsUI is True; otherwise, it is False.

Hands-On 15.13. Writing the Workbook_BeforeSave() Event Procedure

1. In the Visual Basic Editor screen, activate the Project Explorer window and open the Microsoft Excel Objects folder under VBAProject. (Chap15_WorkbookEvents.xlsm). Double-click ThisWorkbook.

2. In the ThisWorkbook Code window, type the Workbook_BeforeSave procedure as shown below:

Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)

If SaveAsUI = True And ThisWorkbook.Path = vbNullString Then

MsgBox "This document has not yet " & "been saved." & vbCrLf & "The Save As dialog box will be displayed."

ElseIf SaveAsUI = True Then

MsgBox "You are not allowed to use " & "the SaveAs option. "

Cancel = True

End If

End Sub

The example procedure displays the Save As dialog box if the workbook hasn’t been saved before. The workbook’s pathname will be a null string (vbNullString) if the file has not been saved before. The procedure will not let the user save the workbook under a different name—the SaveAs operation will be aborted by setting the Cancel argument to True. The user will need to choose the Save option to have the workbook saved.

3. Switch to the Microsoft Excel application window and activate any sheet in the Chap15_WorkbookEvents.xlsm workbook.

4. Make an entry in any cell of this workbook, click the File tab, and choose Save As | Excel Macro-Enabled Workbook.

The Workbook_BeforeSave event procedure will be activated, and the ElseIf clause gets executed. Notice that you are not allowed to save the workbook by using the SaveAs option.

Workbook_BeforePrint(Cancel As Boolean)

This event occurs before the workbook is printed and before the Print dialog appears.

Hands-On 15.14. Writing the Workbook_BeforePrint() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click the ThisWorkbook object in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents.xlsm).

2. In the ThisWorkbook Code window, type the Workbook_BeforePrint event procedure as shown below:

Private Sub Workbook_BeforePrint(Cancel As Boolean)

Dim response As Integer

response = MsgBox("Do you want to " & vbCrLf & "print the workbook’s full name in the footer?", vbYesNo)

If response = vbYes Then

ActiveSheet.PageSetup.LeftFooter = ThisWorkbook.FullName

Else

ActiveSheet.PageSetup.LeftFooter = ""

End If

End Sub

The example procedure places the workbook’s full name in the document footer prior to printing if the user clicks Yes in the message box.

3. Switch to the Microsoft Excel application window and activate any sheet in the Chap15_WorkbookEvents.xlsm workbook.

4. Enter anything you want in any worksheet cell.

5. Click the File | Print, and click the Print button.

Excel will ask you if you want to place the workbook’s name and path in the footer.

Workbook_BeforeClose(Cancel As Boolean)

This event occurs before the workbook is closed and before the user is asked to save changes.

Hands-On 15.15. Writing the Workbook_BeforeClose() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click ThisWorkbook in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents.xlsm).

2. In the ThisWorkbook Code window, type the Workbook_BeforeClose event procedure as shown below:

Private Sub Workbook_BeforeClose(Cancel As Boolean)

If MsgBox("Do you want to change " & vbCrLf & " workbook properties before closing?", vbYesNo) = vbYes Then

Application.Dialogs(xlDialogProperties).Show

End If

End Sub

The example procedure displays the Properties dialog box if the user responds Yes to the message box.

3. Switch to the Microsoft Excel application window, and close the Chap15_WorkbookEvents.xlsm workbook.

Upon closing, you should see a message box asking you to view the Properties dialog box prior to closing. After viewing or modifying the workbook properties, the procedure closes the workbook. If there are any changes that you have not yet saved, you are given the chance to save the workbook, cancel the changes, or abort the closing operation altogether.

Workbook_NewSheet(ByVal Sh As Object)

This event occurs after the user creates a new sheet in a workbook.

Hands-On 15.16. Writing the Workbook_NewSheet() Event Procedure

1. Open a new workbook and save it as Chap15_WorkbookEvents2.xlsm in your C:\VBAExcel2016__ByExample folder.

2. Switch to the Visual Basic Editor window, and in the Project Explorer window, double-click ThisWorkbook in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents2.xlsm).

3. In the ThisWorkbook Code window, type the Workbook_NewSheet event procedure as shown below:

Private Sub Workbook_NewSheet(ByVal Sh As Object)

If MsgBox("Do you want to place " & vbCrLf & "the new sheet at the beginning " & vbCrLf & "of the workbook?", vbYesNo) = vbYes Then

Sh.Move before:=ThisWorkbook.Sheets(1)

Else

Sh.Move After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)

MsgBox Sh.Name & " is now the last sheet in the workbook."

End If

End Sub

The example procedure places the new sheet at the beginning of the workbook if the user responds Yes to the message box; otherwise, the new sheet is placed at the end of the workbook.

4. Switch to the Microsoft Excel application window and click the New Sheet Button (+) (at the bottom of the screen). Excel will ask where to place the new sheet.

Let’s try out some of the events related to operations on workbook windows.

Workbook_WindowActivate(ByVal Wn As Window)

This event occurs when the user shifts the focus to any window showing the workbook.

Hands-On 15.17. Writing the Workbook_WindowActivate() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click the ThisWorkbook object in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents2.xlsm).

2. In the ThisWorkbook Code window, enter the Workbook_WindowActivate event procedure as shown below:

Private Sub Workbook_WindowActivate(ByVal Wn As Window)

Wn.GridlineColor = vbYellow

End Sub

The example procedure changes the color of the worksheet gridlines to yellow when the user activates the workbook containing the code of the Workbook_WindowActivate procedure.

3. Switch to the Microsoft Excel application window and open a new workbook.

4. Arrange Microsoft Excel workbooks vertically on the screen, by choosing View | Arrange All to open the Arrange Windows dialog. Select the Vertical option button and click OK. When you activate the worksheet of the workbook in which you entered the code of the Workbook_WindowActivate event procedure, the color of the gridlines should change to yellow.

Workbook_WindowDeactivate(ByVal Wn As Window)

This event occurs when the user shifts the focus away from any window showing the workbook.

Hands-On 15.18. Writing the Workbook_WindowDeactivate() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click the ThisWorkbook object in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents2.xlsm).

2. In the ThisWorkbook Code window, enter the Workbook_WindowDeactivate procedure as shown below:

Private Sub Workbook_WindowDeactivate(ByVal Wn As Window)

MsgBox "You have just deactivated " & Wn.Caption

End Sub

The example procedure displays the name of the deactivated workbook when the user switches to another workbook from the workbook containing the code of the Workbook_WindowDeactivate procedure.

4. Switch to the Microsoft Excel application window and open a new workbook.

Excel displays the name of the deactivated workbook in a message box.

Workbook_WindowResize(ByVal Wn As Window)

This event occurs when the user opens, resizes, maximizes, or minimizes any window showing the workbook.

Hands-On 15.19. Writing the Workbook_WindowResize() Event Procedure

1. In the Visual Basic Editor window, activate the Project Explorer window and double-click the ThisWorkbook object in the Microsoft Excel Objects folder under VBAProject (Chap15_WorkbookEvents2.xlsm).

2. In the ThisWorkbook Code window, enter the Workbook_WindowResize procedure as shown below:

Private Sub Workbook_WindowResize(ByVal Wn As Window)

If Wn.WindowState <> xlMaximized Then

Wn.Left = 0

Wn.Top = 0

End If

End Sub

The example procedure moves the workbook window to the top left-hand corner of the screen when the user resizes it.

3. Switch to the Microsoft Excel application and activate the Chap15_WorkbookEvents2.xlsm workbook.

4. Click the Restore Window button to the right of the menu bar.

5. Move the Chap15_WorkbookEvents2.xlsm window to the middle of the screen by dragging its title bar.

6. Change the size of the active window by dragging the window borders in or out.

As you complete the sizing operation, the workbook window should automatically jump to the top left-hand corner of the screen.

7. Click the Maximize button to restore the Chap15_WorkbookEvents2.xlsm workbook window to its full size.

An Excel workbook can respond to a number of other events, as shown in Table 15.4.

TABLE 15.4. Additional workbook events

Workbook Event Name

Event Description

SheetActivate

This event occurs when the user activates any sheet in the workbook. The SheetActivate event occurs also at the application level when any sheet in any open workbook is activated.

SheetDeactivate

This event occurs when the user activates a different sheet in a workbook.

SheetSelectionChange

This event occurs when the user changes the selection on a worksheet. This event happens for each sheet in a workbook.

SheetChange

This event occurs when the user changes a cell formula.

SheetCalculate

This event occurs when the user recalculates a worksheet.

SheetBeforeDoubleClick

This event occurs when the user double-clicks a cell on a worksheet.

SheetBeforeRightClick

This event occurs when the user right-clicks a cell on a worksheet.

NewChart

This event occurs when a new chart is created in the workbook.

AfterSave

This event occurs after the workbook is saved.

AddinInstall

This event occurs after the workbook is installed as an add-in.

AddinUninstall

This event occurs when the workbook is uninstalled as an add-in.

SheetFollowHyperlink

This event occurs when you click any hyperlink in Microsoft Excel.

PIVOTTABLE EVENTS

In Excel, PivotTable reports provide a powerful way of analyzing and comparing large amounts of information stored in a database. By rotating rows and columns of a PivotTable report, you can see different views of the source data or see details of the data that interests you the most. When working with PivotTable reports programmatically, you can determine when a PivotTable report opened or closed the connection to its data source by using the PivotTableOpenConnection and PivotTableCloseConnection workbook events and determine when the PivotTable was updated via the SheetPivotTableUpdate event. Table 15.5 lists events related to PivotTable reports. If you haven’t worked with PivotTables programmatically, Chapter 22, “Programming PivotTables and PivotCharts,” will get you started writing VBA code for creating and manipulating PivotTables and PivotCharts. You will find it easier to delve into the PivotTable event programming after working through Chapter 22.

TABLE 15.5. Workbook events related to PivotTable reports

Workbook Event Name

Event Description

PivotTableOpenConnection

Occurs after a PivotTable report opens the connection to its data source. This event requires that you declare an object of type Application or Workbook using the WithEvents keyword in a class module (see examples of using this keyword further in this chapter).

PivotTableCloseConnection

Occurs after a PivotTable report closes the connection to its data source. This event requires that you declare an object of type Application or Workbook using the WithEvents keyword in a class module (see examples of using this keyword further in this chapter).

SheetPivotTableUpdate

TheSheetPivotTableUpdate event procedure takes the following two arguments:

Sh — the selected sheet

Target — the selected PivotTable report

This event occurs after the sheet of the PivotTable report has been updated. This event requires that you declare an object of type Application or Workbook using the WithEvents keyword in a class module (see examples of using this keyword at the end of this chapter).

NOTE

The example event procedure shown below, along with other procedures related to the PivotTable reports, can be found in the Chap15_PivotReportEvents.xlsm downloadable file.

Private Sub pivTbl_SheetPivotTableUpdate(ByVal Sh As Object, ByVal Target As PivotTable)

MsgBox Target.Name & " report has been updated." & vbCrLf & "The PivotReport is located in cells " & Target.DataBodyRange.Address

End Sub

SheetPivotTableChangeSync

This event takes the following two arguments:

Sh — the worksheet that contains the PivotTable

Target — the PivotTable that was changed

This event occurs after changes to a PivotTable. For example, after making changes to a PivotTable you can write code to display a message:

Private Sub Workbook_SheetPivotTableChangeSync(ByVal Sh As Object, ByVal Target As PivotTable)

MsgBox "Thanks for working with " & "PivotTable (" & Target.Name & ") on " & Sh.Name & " worksheet."

End Sub

NOTE

The example event procedure shown above can be found in the Chap15_PivotReportEvents.xlsm downloadable file.

SheetPivotTableAfter ValueChange

This event occurs after a cell or range of cells (that contain formulas) inside a PivotTable are edited or recalculated. This event will not occur when a PivotTable is refreshed, sorted, filtered, or dilled down on.

SheetPivotTableBefore DiscardChanges

This event occurs immediately before changes to a PivotTable are discarded. It is used with the PivotTable’s OLAP (online analytical processing) data source.

SheetPivotTableBefore CommitChanges

This event occurs immediately before changes are committed against the OLAP data source for a PivotTable.

SheetPivotTableBefore AllocateChanges

This event occurs immediately before changes are applied to the PivotTable’s OLAP data source.

CHART EVENTS

As you know, you can create charts in Excel that are embedded in a worksheet or located on a separate chart sheet. In this section, you will learn how to control chart events no matter where you’ve decided to place your chart. Before you try out selected chart events, perform the tasks in Hands-On 15.20.

Hands-On 15.20. Creating Charts for Trying Out Chart Events

1. Open a new Excel workbook and save it as Chap15_ChartEvents.xlsm.

2. Enter sample data as shown in Figure 15.3.

3. Select cells A1:D5, and choose Insert | Charts | Insert Column Chart | 2-D | Clustered Column.

FIGURE 15.3. Column chart embedded in a worksheet.

4. Size the chart as shown in Figure 15.3.

5. Using the same data, create a line chart on a separate chart sheet, as shown in Figure 15.5. To add a new chart sheet, right-click any sheet tab in the workbook and choose Insert. In the Insert dialog box, select Chart and click OK. On the Design tab in the Chart Tools group, click the Select Data button. Excel will display the Select Data Source dialog box. At this point, click the Sheet1 tab and select cells A1:D5. Excel will fill in the Chart data range box in the dialog box as in Figure 15.4. Click OK to complete the chart. Now, change the chart type to Line chart with Markers by choosing the Change Chart Type button in the Chart Tools Design tab. In the Change Chart Type dialog box, select Line chart in the left pane, and click the button representing the Line chart with Markers. Click OK to close the dialog box.

6. Change the name of the chart sheet to Sales Analysis Chart.

FIGURE 15.4. Creating a chart in a chart sheet.

FIGURE 15.5. Line chart placed in a chart sheet.

Writing Event Procedures for a Chart Located on a Chart Sheet

Excel charts can respond to a number of events, as shown in Table 15.6.

TABLE 15.6. Chart events

Chart Event Name

This event occurs when …

Activate

The user activates the chart sheet.

Deactivate

The user deactivates the chart sheet.

Select

The user selects a chart element.

SeriesChange

The user changes the value of a chart data point. The Chart object should be declared in the class module using the WithEvents keyword.

Calculate

The user plots new or changed data on the chart.

Resize

The user changes the size of the chart. The Chart object should be declared in the class module using the WithEvents keyword.

BeforeDoubleClick

An embedded chart is double-clicked, before the default double-click action.

BeforeRightClick

An embedded chart is right-clicked, before the default right-click action.

MouseDown

A mouse button is pressed while the pointer is over a chart.

MouseMove

The position of a mouse pointer changes over a chart.

MouseUp

A mouse button is released while the pointer is over a chart.

We will start by writing event procedures that control a chart placed on a separate chart sheet as shown in Figure 15.5. Events for a chart embedded in a worksheet like the one in Figure 15.3 require using the WithEvents keyword and are explained in the section titled “Writing Event Procedures for Embedded Charts.”

Chart_Activate()

This event occurs when the user activates the chart sheet.

Chart_Deactivate()

This event occurs when the user deactivates the chart sheet.

Chart_Select(ByVal ElementID As Long, ByVal Arg1 As Long, ByVal Arg2 As Long)

This event occurs when the user selects a chart element.

ElementID returns a constant representing the type of the selected chart element. Arguments Arg1 and Arg2 are used in relation to some chart elements. For example, the chart axis (ElementID = 21) can be specified as Main Axis (Arg1 = 0) or Secondary Axis (Arg1 = 1), while the axis type is specified by Arg2, which can be one of the following three values: 0 – Category Axis, 1 – Value Axis, and 3 – Series Axis.

Chart_Calculate()

This event occurs when the user plots new or changed data on the chart.

Chart_BeforeRightClick()

This event occurs when the user right-clicks the chart.

Chart_MouseDown(ByVal Button As Long, ByVal Shift As Long, ByVal x As Long, ByVal y As Long)

This event occurs when a mouse button is pressed while the pointer is over a chart.

The Button argument determines which mouse button was pressed (MouseDown event) or released (MouseUp event): 1 – left button, 2 – right button, and 4 – middle button. The Shift argument specifies the state of the Shift, Ctrl, and Alt keys: 1 – Shift was selected, 2 – Ctrl was selected, 4 – Alt was selected. The x, y arguments specify the mouse pointer coordinates.

Hands-On 15.21. Writing Event Procedures for a Chart Sheet

1. In the Visual Basic Editor window, activate the Project Explorer window and open the Microsoft Excel Objects folder under VBAProject (Chap15_ChartEvents.xlsm).

2. Double-click the chart object Chart1 (Sales Analysis Chart).

3. In the Code window, enter the code of the following event procedures:

Private Sub Chart_Activate()

MsgBox "You’ve activated the chart sheet."

End Sub

Private Sub Chart_Deactivate()

MsgBox "It looks like you want to leave the " & "chart sheet."

End Sub

Private Sub Chart_Select(ByVal ElementID As Long, ByVal Arg1 As Long, ByVal Arg2 As Long)

If Arg1 <> 0 And Arg2 <> 0 Then

MsgBox ElementID & ", " & Arg1 & ", " & Arg2

End If

If ElementID = 4 Then

MsgBox "You’ve selected the chart title."

ElseIf ElementID = 24 Then

MsgBox "You’ve selected the chart legend."

ElseIf ElementID = 12 Then

MsgBox "You’ve selected the legend key."

ElseIf ElementID = 13 Then

MsgBox "You’ve selected the legend entry."

End If

End Sub

Private Sub Chart_Calculate()

MsgBox "The data in your spreadsheet has " & vbCrLf & "changed. Your chart has been updated."

End Sub

Private Sub Chart_BeforeRightClick(Cancel As Boolean)

Cancel = True

End Sub

Private Sub Chart_MouseDown(ByVal Button As Long, ByVal Shift As Long, ByVal x As Long, ByVal y As Long)

If Button = 1 Then

MsgBox "You pressed the left mouse button."

ElseIf Button = 2 Then

MsgBox "You pressed the right mouse button."

Else

MsgBox "You pressed the middle mouse button."

End If

End Sub

4. Activate the chart sheet and perform the actions that will trigger the event procedures that you’ve written. For example, click the chart legend and notice that this action triggers two events: Chart_MouseDown and Chart_Select.

Writing Event Procedures for Embedded Charts

To capture events raised by a chart embedded in a worksheet, you must first create a new object in the class module using the keyword WithEvents.

The WithEvents keyword allows you to specify an object variable that will be used to respond to events triggered by an ActiveX object. This keyword can only be used in class modules in the declaration section. In the following example procedure, we will learn how to use the WithEvents keyword to capture the Chart_Activate event for the embedded chart you created in Hands-On 15.20.

Hands-On 15.22. Writing the Chart_Activate() Event Procedure for an Embedded Chart

1. Activate the Visual Basic Editor window. In the Project Explorer, select VBAProject (Chap15_ChartEvents.xlsm).

2. Choose Insert | Class Module.

In the Class Modules folder, you will see a module named Class1.

3. In the Properties window, rename Class1 to clsChart.

4. In the clsChart class module Code window, type the following declaration:

Public WithEvents xlChart As Excel.Chart

The above statement declares an object variable that will represent the events generated by the Chart object.

The Public keyword will make the object variable xlChart available to all modules in the current VBA project. Declaring an object variable using the WithEvents keyword exposes all of the events defined for that particular object type. After typing the above declaration, the xlChart object variable is added to the drop-down Object list in the upper-left corner of the Code window, and the events associated with this object variable appear in the Procedure drop-down listbox in the upper-right corner of the Code window.

5. Open the Object drop-down listbox and select the xlChart variable.

The Code window should now show the skeleton of the xlChart_Activate event procedure:

Private Sub xlChart_Activate()

End Sub

6. Add your VBA code to the event procedure. In this example, we will add a statement to display a message box. After adding this statement, your VBA procedure should look like the following:

Private Sub xlChart_Activate()

MsgBox "You’ve activated a chart embedded in " & ActiveSheet.Name & "."

End Sub

After entering the code of the event procedure, you need to inform Visual Basic that you are planning on using it (see Step 7).

7. In the Project Explorer window, double-click the object named ThisWorkbook, and enter in the first line of the ThisWorkbook Code window the statement to create a new instance of the class named clsChart:

Dim myChart As New clsChart

This instruction declares an object variable named myChart. This variable will refer to the xlChart object located in the class module clsChart. The New keyword tells Visual Basic to create a new instance of the specified object.

Before you can use the myChart object variable, you must write a VBA procedure that initializes it (see Step 8).

8. Enter the following procedure in the ThisWorkbook Code window to initialize the object variable myChart:

Sub InitializeChart()

' you must run this procedure before event procedures

' written in clsChart class module can be triggered for

' the chart embedded in Sheet1

' connect the class module with the Excel chart object

Set myChart.xlChart = Worksheets("Sheet1").ChartObjects(1).Chart

End Sub

9. Run the InitializeChart procedure.

After running this procedure, the event procedures entered in the clsChart class module will be triggered in response to a particular event. Recall that right now the clsChart class module contains the Chart_Activate event procedure. Later on you may want to write in the clsChart class module additional event procedures to capture other events for your embedded chart.

10. Activate the Microsoft Excel application window and click the embedded chart in Sheet1.

At this time, the xlChart_Activate event procedure that you entered in Step 6 above should be triggered.

11. Save and close the Chap15_ChartEvents.xlsm workbook file.

EVENTS RECOGNIZED BY THE APPLICATION OBJECT

If you want your event procedure to execute no matter which Excel workbook is currently active, you need to create the event procedure for the Application object. Event procedures for the Application object have a global scope. This means that the procedure code will be executed in response to a certain event as long as the Microsoft Excel application remains open.

Events for the Application object are listed in Table 15.7. Similar to an embedded chart, event procedures for the Application object require that you create a new object using the WithEvents keyword in a class module.

TABLE 15.7. Application events

Application Event Name

Event Description

AfterCalculate

This event occurs whenever all pending calculations and all of the resultant calculation activities have been completed and there are no outstanding queries.

NewWorkbook

This event occurs when the user creates a new workbook.

ProtectedViewWindowActivate

This event occurs when a Protected View window is activated.

ProtectedViewWindowBeforeClose

This event occurs immediately before a Protected View window or a workbook in a Protected View window opens.

ProtectedViewWindowBeforeEdit

This event occurs immediately before editing is enabled on the workbook in the specified Protected View window.

ProtectedViewWindowDeactivate

This event occurs when a Protected View window is deactivated.

ProtectedViewWindowOpen

This event occurs when a workbook is opened in a Protected View.

ProtectedViewWindowResize

This event occurs when any Protected View window is resized.

WorkbookOpen

This event occurs when the user opens a workbook.

WorkbookActivate

This event occurs when the user shifts the focus to an open workbook.

WorkbookDeactivate

This event occurs when the user shifts the focus away from an open workbook.

WorkbookNewSheet

This event occurs when the user adds a new sheet to an open workbook.

WorkbookNewChart

This event occurs when a new chart is created in any open workbook. If multiple charts are inserted or pasted, the event will occur for each chart in the insertion order. If a chart object or chart sheet is moved from one location to another, the event will not occur. However, the event will occur if the chart is moved between a chart object and a chart sheet.

WorkbookBeforeSave

This event occurs before an open workbook is saved.

WorkbookBeforePrint

This event occurs before an open workbook is printed.

WorkbookBeforeClose

This event occurs before an open workbook is closed.

WorkbookAddInInstall

This event occurs when the user installs a workbook as an add-in.

WorkbookAddInUninstall

This event occurs when the user uninstalls a workbook as an add-in.

WorkbookAfterSave

This event occurs after the workbook is saved.

WorkbookRowsetComplete

This event occurs when the user either drills through the recordset or invokes the rowset action on an OLAP PivotTable.

SheetActivate

This event occurs when the user activates a sheet in an open workbook.

SheetDeactivate

This event occurs when the user deactivates a sheet in an open workbook.

SheetFollowHyperlink

This event occurs when the user clicks any hyperlink in Microsoft Excel.

SheetPivotTableAfterValueChanged

This event occurs after a cell or range of cells that contain formulas inside a PivotTable are edited or recalculated.

SheetPivotTableBeforeAllocateChanges

This event occurs before changes are applied to a PivotTable.

SheetPivotTableBeforeCommitChanges

This event occurs before changes are committed against the OLAP data source for a PivotTable (immediately before Excel executes a COMMIT TRANSACTION).

SheetPivotTableBeforeDiscardChanges

This event occurs before changes to a PivotTable are discarded.

SheetPivotTableUpdate

This event occurs after the sheet of the PivotTable report has been updated.

SheetSelectionChange

This event occurs when the user changes the selection on a sheet in an open workbook.

SheetChange

This event occurs when the user changes a cell formula in an open workbook.

SheetCalculate

This event occurs when the user recalculates a worksheet in an open workbook.

SheetBeforeDoubleClick

This event occurs when the user double-clicks a worksheet cell in an open workbook.

SheetBeforeRightClick

This event occurs when the user right-clicks a worksheet cell in an open workbook.

WindowActivate

This event occurs when the user shifts the focus to an open window.

WindowDeactivate

This event occurs when the user shifts the focus away from the open window.

WindowResize

This event occurs when the user resizes an open window.

WorkbookPivotTableCloseConnection

This event occurs after a PivotTable report connection has been closed.

WorkbookPivotTableOpenConnection

This event occurs after a PivotTable report connection has been opened.

WorkbookAfterXmlExport

This event occurs after Microsoft Excel saves or exports data from any open workbook to an XML data file.

WorkbookAfterXmlImport

This event occurs after an existing XML data connection is refreshed or new XML data is imported into any open Microsoft Excel workbook.

WorkbookBeforeXmlExport

This event occurs before Microsoft Excel saves or exports data from any open workbook to an XML data file.

WorkbookBeforeXmlImport

This event occurs before an existing XML data connection is refreshed or new XML data is imported into any open Microsoft Excel workbook.

WorkbookSync

This event occurs when the local copy of a workbook that is part of a document workspace is synchronized with the copy on the server. This event has been deprecated; it’s used only for backward compatibility.

Let’s try a couple of event procedures for the Application object.

Hands-On 15.23. Writing Event Procedures for the Application Object

1. Open a new workbook and save it as Chap15_ApplicationEvents.xlsm in C:\VBAExcel2016__ByExample.

2. Switch to the Visual Basic Editor window, and in the Project Explorer window select VBAProject (Chap15_ApplicationEvents.xlsm).

3. Choose Insert | Class Module.

4. In the Properties window, change the class module name to clsApplication.

5. In the clsApplication Code window, type the following declaration statement:

Public WithEvents App As Application

This statement uses the WithEvents keyword to declare an Application object variable.

6. Below the declaration statement, enter the event procedures as shown below:

Private Sub App_WorkbookOpen(ByVal Wb As Workbook)

If Wb.FileFormat = xlCSV Then

If MsgBox("Do you want to save this " & vbCrLf & "file as an Excel workbook?", vbYesNo, "Original file format: " & "comma delimited file") = vbYes Then

Wb.SaveAs FileFormat:=xlWorkbookNormal

End If

End If

End Sub

Private Sub App_WorkbookBeforeSave(ByVal Wb As Workbook, ByVal SaveAsUI As Boolean, Cancel As Boolean)

If Wb.Path <> vbNullString Then

ActiveWindow.Caption = Wb.FullName & " [Last Saved: " & Time & "]"

End If

End Sub

Private Sub App_WorkbookBeforePrint(ByVal Wb As Workbook, Cancel As Boolean)

Wb.PrintOut Copies:=2

End Sub

Private Sub App_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)

Dim r As Integer

Dim p As Variant

Sheets.Add

r = 1

For Each p In Wb.BuiltinDocumentProperties

On Error GoTo ErrorHandle

Cells(r, 1).Value = p.Name & " = " & ActiveWorkbook.BuiltinDocumentProperties.Item(p.Name).Value

r = r + 1

Next

Exit Sub

ErrorHandle:

Cells(r, 1).Value = p.Name

Resume Next

End Sub

Private Sub App_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

If Selection.Count > 1 Or (Selection.Count < 2 And IsEmpty(Target.Value)) Then

Application.StatusBar = Target.Address

Else

Application.StatusBar = Target.Address & "(" & Target.Value & ")"

End If

End Sub

Private Sub App_WindowActivate(ByVal Wb As Workbook, ByVal Wn As Window)

Wn.DisplayFormulas = True

End Sub

7. After you’ve entered the code of the above event procedures in the class module, choose Insert | Module to insert a standard module into your current VBA project.

8. In the newly inserted standard module, create a new instance of the clsApplication class and connect the object located in the class module clsApplication with the object variable App representing the Application object, as shown below:

Dim DoThis As New clsApplication

Public Sub InitializeAppEvents()

Set DoThis.App = Application

End Sub

Recall that you declared the App object variable to point to the Application object in Step 5 above.

9. Now place the mouse pointer within the InitializeAppEvents procedure and press F5 to run it.

As a result of running the InitializeAppEvents procedure, the App object in the class module will refer to the Excel application. From now on, when a specific event occurs, the code of the event procedures you’ve entered in the class module will be executed.

If you don’t want to respond to events generated by the Application object, you can break the connection between the object and its object variable by entering in a standard module (and then running) the following procedure:

Public Sub CancelAppEvents()

Set DoThis.App = Nothing

End Sub

When you set the object variable to Nothing, you release the memory and break the connection between the object variable and the object to which this variable refers. When you run the CancelAppEvents procedure, the code of the event procedures written in the class module will not be automatically executed when a specific event occurs.

Now let’s proceed to try triggering the application events you coded in the class module.

10. Switch to the Chap15_ApplicationEvents workbook in the Excel application window. Click the File tab and choose New. Select Blank Workbook, and click Create.

11. Click the File tab and choose Save As. Save the workbook opened in Step 10 as TestBeforeSaveEvent.xlsx.

12. Type anything in Sheet1 of the TestBeforeSaveEvent.xlsx workbook and save this workbook.

Notice that Excel writes the full name of the workbook file and the time the workbook was last saved in the workbook’s title bar as coded in the WorkbookBeforeSave event procedure (see Step 6). Every time you save this workbook file, Excel will update the last saved time in the workbook’s title bar.

13. Take a look at the code in other event procedures you entered in Step 6 and perform actions that will trigger these events.

14. Close the Chap15_ApplicationEvents.xlsm file and other workbooks if they are currently open.

QUERY TABLE EVENTS

A query table is a table in an Excel worksheet that represents data returned from an external data source, such as an SQL Server database, a Microsoft Access database, a Web page, or a text file. Excel provides two events for the QueryTable object: BeforeRefresh and AfterRefresh. These events are triggered before or after the query table is refreshed. You can create a query table as a standalone object or as a list object whose data source is a query table. The list object is discussed in detail in Chapter 21, “Using and Programming Excel Tables.”

When you retrieve data from an external data source such as Access or SQL Server using the controls available on the Excel Ribbon’s Data tab, Excel creates a query table that is associated with a list object. The resulting table is easier to use thanks to a number of built-in data management features available on the Ribbon. The next Hands-On demonstrates how to create a query table associated with a list object and enable the QueryTable object’s BeforeRefresh and AfterRefresh events. This exercise assumes that you have Microsoft Access and a sample Northwind 2007.accdb database installed on your computer.

Hands-On 15.24. Writing Event Procedures for a Query Table

1. Open a new Microsoft Excel workbook and save it as Chap15_QueryTableEvents.xlsm in your C:\VBAExcel2016__ByExample folder.

2. Choose the Data tab. In the Get External Data group, click the From Other Sources button and choose From Microsoft Query.

3. In the Choose Data Source dialog box, select <New Data Source> and click OK.

4. In Step 1 of the Create New Data Source dialog box, enter SampleDb as the data source name, as shown in Figure 15.6.

FIGURE 15.6. Use the Create New Data Source dialog box to specify the data source that will provide data for the query table.

5. In Step 2 of the Create New Data Source dialog box, select Microsoft Access Driver (*.mdb, *.accdb) from the drop-down list.

6. In Step 3 of the Create New Data Source dialog box, click the Connect button.

7. In the ODBC Microsoft Access Setup dialog box, click the Select button.

8. In the Select Database dialog box, navigate to the C:\VBAExcel2016__ByExample folder and select the Northwind 2007.accdb file, then click OK to close the Select Database dialog box.

9. In Step 4 of the Create New Data Source dialog box, select the Inventory on Order table in the drop-down listbox, as shown in Figure 15.7.

FIGURE 15.7 Use Step 4 of the Create New Data Source dialog to specify a default table for your data source.

10. Click OK to close the Create New Data Source dialog box.

11. In the Choose Data Source dialog box, the SampleDb data source name should now be highlighted. Click OK.

12. In the Query Wizard–Choose Columns dialog box, click the button with the greater than sign (>) to move all the fields from the Inventory on Order table to the Columns in your query box.

13. Click the Next button until you get to the Query Wizard–Finish dialog box.

14. In the wizard’s Finish dialog box, make sure the Return Data to Microsoft Excel option button is selected and click Finish.

15. In the Import Data dialog box, the current worksheet cell is selected. Click cell A1 in the current worksheet to change the cell reference. Next, click the Properties button. Excel will display the Connection Properties dialog box. Check Refresh the data when opening the file and click OK. Click OK to exit the Import Data dialog box.

After completing the above steps, the data from the Inventory on Order table in the Northwind 2007 database should be placed in the active worksheet.

To write event procedures for a QueryTable object, you must create a class module and declare a QueryTable object by using the WithEvents keyword. Let’s continue.

16. Save the changes in the Chap15_QueryTableEvents.xlsm workbook.

17. Switch to the Visual Basic Editor window and insert a class module into VBAProject (Chap15_QueryTableEvents.xlsm).

18. In the Properties window, rename the class module clsQryTbl.

19. In the clsQryTbl Code window, type the following declaration statement:

Public WithEvents qryTbl As QueryTable

After you’ve declared the new object (qryTbl) by using the WithEvents keyword, it appears in the Object drop-down listbox in the class module.

20. In the clsQryTbl Code window, enter the two event procedures shown below:

Private Sub qryTbl_BeforeRefresh(Cancel As Boolean)

Dim Response As Integer

Response = MsgBox("Are you sure you " & " want to refresh now?", vbYesNoCancel)

If Response = vbNo Then Cancel = True

End Sub

Private Sub qryTbl_AfterRefresh(ByVal Success As Boolean)

If Success Then

MsgBox "The data has been refreshed."

Else

MsgBox "The query failed."

End If

End Sub

The BeforeRefresh event of the QueryTable object occurs before the query table is refreshed. The AfterRefresh event occurs after a query is completed or canceled. The Success argument is True if the query was completed successfully.

Before you can trigger these event procedures, you must connect the object that you declared in the class module (qryTbl) to the specified QueryTable object. This is done in a standard module as shown in Step 21.

21. Insert a standard module into VBAProject (Chap15_QueryTableEvents.xlsm) and rename it QueryTableListObj.

22. In the QueryTableListObj Code window, enter the declaration line and the procedure as shown below:

Dim sampleQry As New clsQryTbl

Public Sub Auto_Open()

' connect the class module and its objects with the Query object

Set sampleQry.qryTbl = ActiveSheet.ListObjects(1).QueryTable

End Sub

This procedure creates a new instance of the QueryTable class (clsQryTbl) and connects this instance with the first list object on the active worksheet.

 

NOTE

A query table associated with a list object can only be accessed through the ListObject.QueryTable property. This query table is not a part of the Worksheet. QueryTables collection. To find out whether a query table exists on a worksheet, be sure to check both the QueryTables and ListObjects collections. This can be done easily by entering in the Immediate window the following statements:

?ActiveSheet.ListObjects.Count

?ActiveSheet.QueryTables.Count

23. Run the Auto_Open procedure.

After you run this initialization procedure, the object that you declared in the class module points to the specified QueryTable object.

 

NOTE

In the future when you want to work with the QueryTable object in this workbook file, you won’t need to run the Auto_Open procedure. This procedure will run automatically upon opening the workbook file.

24. Switch to the Microsoft Excel application window. In the worksheet where you placed the Inventory on Order table from the Microsoft Access database, choose Data | Refresh All. Excel will now trigger the qryTbl_BeforeRefresh event procedure and you should see the custom message box. If you click Yes, the data in the worksheet will be refreshed with the existing data in the database. Excel will then trigger the qryTbl_AfterRefresh event procedure and another custom message will be displayed.

25. Close the Chap15_QueryTableEvents.xlsm workbook file.

OTHER EXCEL EVENTS

There are two events in Excel that are not associated with a specific object: the OnTime and OnKey events. These events are accessed using the methods of the Application Object: OnTime and OnKey.

OnTime Method

The OnTime event uses the OnTime method of the Application object to trigger an event at a specific time. The syntax is:

Application.OnTime(EarliestTime, Procedure, LatestTime, Schedule)

The Procedure parameter is the name of the VBA procedure to run. The EarliestTime parameter is the time you would like the procedure to run. Use the TimeValue function to specify time as shown in the examples below. LatestTime is an optional parameter that allows you to specify the latest time the procedure can be run. Again, you can use the TimeValue function to specify a time for this parameter. The Schedule parameter allows you to clear a previously set OnTime event. Set this parameter to False to cancel the event. The default value for Schedule is True.

For example, you can have Excel run the specified procedure at 4:00 p.m. as shown below:

Application.OnTime TimeValue("4:00PM"), "YourProcedureName"

To cancel the above event, run the following code:

Application.OnTime TimeValue("4:00PM"), "YourProcedureName", , False

To schedule the procedure five minutes after the current time, use the following code:

Application.OnTime Now + TimeValue("00:05:00"), "YourProcedureName"

The Now function returns the current time. Therefore, to schedule the procedure to occur in the future (a certain amount from the current time), you need to set the value of the EarliestTime parameter to:

Now + TimeValue(time)

To trigger your procedure on July 4, 2016, at 12:01 a.m., type the following statement on one line in the Immediate window and press Enter:

Application.OnTime DateSerial(2016, 7, 4) + TimeValue("00:00:01"), "YourProcedureName"

OnKey Method

You can use the Application object’s OnKey method to trigger a procedure whenever a particular key or key combination is pressed. The syntax of the OnKey method is as follows:

Application.OnKey(Key, Procedure)

where Key is a string indicating the key to be pressed and Procedure is the name of the procedure you want to execute. If you pass an empty string (“”) as the second parameter for the OnKey method, Excel will ignore the keystroke.

The key parameter can specify a single key or any key combined with Shift, Alt, and/or Ctrl. For a letter, or any other character key, use that character. To specify a key combination, use the plus sign (+) for Shift, percent sign (%) for Alt, and caret (^) for Ctrl in front of the keycode.

For example, to run your procedure when you press Ctrl-a, you would write the following statement:

Application.OnKey "^a", "YourProcedureName"

Special keys are entered using curly braces: {Enter}, {Down}, {Esc}, {Home}, {Backspace}, {F1} or {Right}. See the list of keycodes in Table 13.4 (Chapter 13). For example, to run the procedure named “NewFolder” when the user presses Alt-F10, use the following code:

Application.OnKey "%{F10}", "NewFolder"

To cancel an OnKey event and return the key to its normal function, call the OnKey method without the Procedure parameter:

Application.OnKey "%{F10}"

The above code will return the key combination Alt+F10 to its default function in Excel, which is to display the Selection and Visibility pane on the right side of the Excel screen.

While using the OnKey method is a quick way to assign a shortcut to execute a VBA procedure or macro, a better way is to use the Options button in the Macro dialog to assign a Ctrl+key combination to a procedure.

When using the OnKey events, keep in mind that reassigning frequently used Excel shortcuts (such as Ctrl+P for Print) to perform other customized processes may make you an unpopular developer among your users.

SUMMARY

In this chapter, you gained hands-on experience with events and event-driven programming in Excel. These are invaluable skills, whether you are planning to create spreadsheet applications for others to use or simply automating your worksheet daily tasks. Excel provides many events to which you can respond. By writing event procedures, you can change the way objects respond to events. Your event procedures can be as simple as a single line of code displaying a custom message, or more complex with code including decision-making statements and other programming structures that allow you to change the flow of your program when a particular event occurs. When a certain event occurs, Visual Basic will simply run an appropriate event procedure instead of responding in the standard way. You’ve learned that some event procedures are written in a standard module (workbook, worksheet, and standalone chart sheet) while others (embedded chart, application, and query table) require that you create a new object using the WithEvents keyword in a class module. You’ve also learned that you can enable or disable events using the EnableEvents property. In the final section of this chapter you also learned how to use two Application object methods to execute procedures at a specific time or in response to the user pressing a key or a key combination.

The next chapter takes you through the process of accessing Excel dialog boxes with VBA.