3 4
If you've written any Microsoft Visual Basic code, you've almost certainly written event procedures. An event procedure contains code that is executed when an event occurs. For example, a Visual Basic form with a button can have a procedure to handle the button's Click event. And writing code behind events in the Microsoft Visual Basic for Applications (VBA) environment in the Visio application is the same as writing code behind events in any other VBA host application; for example, any Microsoft Office application.
Every VBA project in Visio is set up to capture the events raised by the Document object associated with the project (ThisDocument). To respond to events raised by other Visio objects, you can declare object variables using the WithEvents keyword, which exposes all of the events defined for that particular object type, and provides skeleton event-handling procedures in your project. All you need to do is write code for the events you want to handle.
WithEvents object variables must be declared in class modules. You can declare them in the ThisDocument class, which is a default class module in every Visio VBA project, or you can declare WithEvents object variables in a separate class module that you insert into your project.
Writing code behind events is also a way to handle the events raised by any Microsoft ActiveX controls that you have inserted into your project. For details on handling events for an ActiveX control, see Chapter 24, Using ActiveX Controls in a Visio Solution.
Note
All the information in this section also applies to a stand-alone Visual Basic project with the following exception: You need to set a reference to the Visio type library from your Visual Basic project. (In Visual Basic, click References on the Projects menu, and then select the Microsoft Visio 2002 type library.)
Every Visio VBA project contains a ThisDocument class module that responds automatically to the events raised by the Document object associated with your project.
For details about using the Visual Basic Editor, see Chapter 15, Programming Visio with VBA.
The list box in the upper-left corner of the Code window is the Object box; the list box in the upper-right corner is the Procedure box.
Figure 21-2 The ThisDocument code window.(A) Object box,(B) Code window for ThisDocument with a skeleton procedure.(C) Procedure box .
The following example handles two events, DocumentOpened and ShapeAdded, to keep count of shapes (based on a master called Square) that are added to a drawing:
'Number of squares added to drawing Dim intSquares As Integer Private Sub Document_DocumentOpened(ByVal Doc as IVDocument) 'Initialize number of squares added intSquares = 0 End Sub Private Sub Document_ShapeAdded(ByVal Shape As IVShape) Dim mastObj As Master 'Get the Master property of the shape. Set mastObj = Shape.Master 'Check whether the shape has a master. If not, the shape was 'created locally. If Not ( mastObj Is Nothing ) Then 'Check whether the master is "Square". If mastObj.Name = "Square" Then 'Increment the count for the number of 'squares added. intSquares = intSquares + 1 End If End If MsgBox "Number of squares: " & intSquares, vbInformation End Sub
To handle events raised by Visio objects other than your project's document, you can use the VBA keyword WithEvents to declare an object variable for the Visio object whose events you want to handle. The following example describes setting up an object variable to handle the events raised by a Page object.
In ThisDocument, you declare an object variable using the WithEvents keyword and a Visio object type:
Dim WithEvents pageObj As Visio.Page
In addition to the usual access to an object's properties and methods, using the keyword WithEvents in this declaration gives the object variable the capacity to handle events fired by the Page object assigned to that variable. All events in the object's event set will be fired, and you provide code for the events that you want to handle.
By declaring this WithEvents variable as type Visio.Page, VBA can identify the type library (Visio) and the event set (Page) that it needs to capture. Now when you select pageObj in the Object box in the Visual Basic Editor, the Procedure box shows the events that are fired by the Page object.
For example, the following event procedure prints the names of shapes in the Immediate window whenever a shape is deleted from the active page of your project, which is represented by pageObj :
Public Sub pageObj_BeforeShapeDelete (ByVal Shape As IVShape) Debug.Print Shape.Name End Sub
Before this procedure will run, however, you must connect the declared object (pageObj) with an instance of the object. Because this connection must be made before the BeforeShapeDelete event fires, you might put this statement in an event procedure for an event that you know will execute before BeforeShapeDelete, such as the document's DocumentOpened event. For example:
Private Sub Document_DocumentOpened(ByVal doc As IVDocument) Set pageObj = ActivePage End Sub
When you are finished with an object reference it is a good practice to release the variable reference. This is often done in the BeforeDocumentClose event handler. For example:
Private Sub Document_BeforeDocumentClose(ByVal doc As IVDocument) set pageObj = Nothing End Sub
For details about the WithEvents keyword, see your Visual Basic or VBA documentation.
You can streamline the process of handling events fired by a particular kind of Visio object by defining a class that contains your event variables and event-handling code. Writing code behind events in a class module works very much the same way as writing code behind events in ThisDocument. When you use a class module to receive events, however, you must create an instance of your class and connect it to a real object. (The ThisDocument object is instantiated and connected to the Document object associated with your project by default.)
When handling events in a separate class module, you write code in two places, your class module and your program.
To add a class to your project, on the Insert menu, click Class Module. You can name this class whatever you want. Place all your event-handling code in this class. Let's say that you want to handle events from a Visio instance in your project—in this case, the source object is an Application object.
Dim WithEvents appObj As Visio.Application
Set appObj = Application
Your event handler is in place, but nothing will happen until you define and create an instance of your class.
Dim MyClass1 As MySinkClass
Set MyClass1 = New MySinkClass
When you create an instance of your class, its Initialize event fires and the WithEvents variable is connected with a real object (see step 3 of the procedure in the previous section, Code in your class module). When you are finished with the instance of your class, release it by setting it to Nothing. This is often done in the BeforeDocumentClose event in your program:
Set MyClass1 = Nothing
For details about the New keyword, see your Visual Basic or VBA documentation.
The following example demonstrates a Visio project that uses a WithEvents variable to monitor events that are happening in a Visio instance. When this project is running, this event handler will display the document and shape name of any shape that is added to any document open in the Visio instance.
The project defines a class called Listener. In the Listener class, do the following:
'Code in the Class Module named Listener Dim WithEvents m_app As Visio.Application Private Sub Class_Initialize() Set m_app = Application End Sub Private Sub Class_Terminate() Set m_app = Nothing End Sub Private Sub m_app_ShapeAdded(ByVal Shape As IVShape) Debug.Print Shape.Document.Name; "/"; Shape.Name End Sub
In ThisDocument, do the following:
'Code in ThisDocument Dim m_listener As Listener Private Sub Document_RunModeEntered(ByVal doc As IVDocument) Set m_listener = New Listener End Sub Private Sub Document_DesignModeEntered(ByVal doc As IVDocument) Set m_listener = Nothing End Sub Private Sub Document_BeforeDocumentClose(ByVal doc As IVDocument) Set m_listener = Nothing End Sub