Hour 22

Object Basics

Considering that Visual Basic is not a true object-oriented language (due to Visual Basic's lack of inheritance features), Visual Basic sure uses a lot of objects! Everything seems to be an object in Visual Basic, including forms, windows, toolbox tools, and ActiveX controls.

This lesson discusses several of the more advanced programming topics that surround objects. By the time you finish this lesson, you will better understand how objects fit into the Visual Basic environment.

The highlights of this hour include

The System Objects

You've worked with several Visual Basic objects already. The Printer object is an object you use with a Print method to send output to the printer, as in the following statement:

Printer.Print Tab(15); "Company Balance Sheet"

In addition, you've seen the Debug object when printing to the Immediate window like this:

Debug.Print "intVar is "; intVar

In both cases, the object represents an item outside your application's scope. The printer and the Immediate window are not your application's; therefore, Visual Basic uses objects to represent them. The Printer object does not reference any particular printer; rather, the Printer object references the current Windows printer. The Debug object represents the Immediate window.

New Term: A system object is an object defined by Visual Basic that lies outside your program's immediate scope.

The Printer and the Debug objects are system objects predefined by the Visual Basic system. Although a command button on your form is an object, the command button is not a system object because the object did not really exist (only its pattern existed on the Toolbox window) before you placed the command button on the form.

Table 22.1 lists all the predefined system objects your applications can work with.

Table 22.1. The system objects and their methods.
Object Description Methods
App Your current application The method called EXEName returns the application's filename. Path returns the application's path. Title returns the primary startup form's title bar text. Previnstance returns True or False to indicate whether another instance (copy) of the application is currently running.
ClipBoard The Windows Clipboard The method Clear erases the Clipboard. GetData returns the graphic image stored on the Clipboard. GetFormat returns the format of the Clipboard object. GetText returns the text on the Clipboard. SetData copies a graphic image to the Clipboard. SetText copies text to the Clipboard. SelStart, SelLength, and SelText perform the Clipboard's selection operations.
Debug The Immediate window The method Print copies information, at runtime, to the Immediate window (only possible in non-.EXE Visual Basic programs you run from Visual Basic's development environment).
Printer The system printer Provides printer support.
Screen The user's screen FontCount returns the number of fonts the current screen supports. Fonts contains a list of all of the screen's possible font names. Height returns the twip height of the screen area. MousePointer holds (or determines if you specify a new one) the shape of the mouse cursor. TwipsPerPixelX returns the number of possible horizontal twips. TwipsPerPixelY returns the number of possible vertical twips. Width returns the width, in twips, of the screen.

Use these objects and methods to return information about the objects. For example, you could append the current application pathname to a string variable like this:

strFullName = Application.Path & "Afile.dat"

Although you won't use the system objects in every application, they do come in handy when you're performing interaction with the Windows Clipboard or the screen.


TIP: The Screen object's measurements differ depending on the video card, resolution, and monitor your user uses. Therefore, the Screen object, available at runtime, represents the entire Windows Desktop. If you want to center a form in the middle of the user's screen, you could place these statements at the beginning of the Form_Load() event procedure:

frmName.Left = (Screen.Width - frmName.Width) / 2
frmName.Top = (Screen.Height - frmName.Height) / 2



Program Objects

New Term: A class is a packaged object, with behaviors and properties, that describes members of the class.

Objects that you create with your application are objects that are members of a particular class. For example, an option button class defines properties, events, and methods that all members of the option button class support. In other words, even though your application may contain five option buttons, and even though all five of those option buttons differ in one or more of their properties (such as Caption), they are all members of the same class. A command button can never be a member of the option button class because a command button's properties, events, and methods differ from an option button's.

You can test for membership within any given class. The class forms a hierarchy and all members of the class take on the class properties, events, and methods. One of the reasons for a class test is that you can pass to procedures not only variables, but also controls. The following procedure receives a command button as its only argument:

Public Sub GetIt(cmdClick As CommandButton)

Some procedures can be multipurpose. In other words, a procedure might change the BackColor property of whatever object you pass to that procedure. Use the As Object argument declaration as follows to make the procedure multipurpose:

Public Sub ChangeColor(objOnForm As Object)

You've not seen the Object keyword until now, but you can declare not only arguments as Object data types, but variables as well, like this:

Dim objAnything As Object

The objAnything variable can now represent an object.

Your application's code can create any object needed at runtime. In other words, you could declare an array of five option buttons like this:

Dim ctlOpButtons(1 To 5) As New OptionButton

The New keyword tells Visual Basic to create five new option buttons. If you want to base a new object on an existing object, you only need to change the properties that differ in the new object from the old one. The following statement declares a new form based on an existing form named frmAcctsPay:

Dim frmNewForm As New frmAcctsPay

Notice that if you place an existing control name after the New statement, Visual Basic declares a new object based on an existing one. If you use a control's class name (such as CommandButton, Form, OptionButton, or Label), Visual Basic declares a new control with all default property values (except for the Name property, which you set with the Dim as you declare the control). You the can specify the property values that you want for your new object.

Use the If TypeOf-Is programming block to test for an object's data type. The following If generates True if the object stored in objAnything is a text box:

If TypeOf objAnything Is TextBox Then

In addition to being a keyword command, Visual Basic supports the TypeOf() function that returns the object type of its argument.

Knowing about an object's class lets Visual Basic accept the following code that contains a With keyword block:

With lblTitle
   .Caption = "Accounts Payable"
   .Alignment = vbRightJustify
   .Font.Size = 15
   .Font.Bold = True
   .Left = 25
   .Right = 0
   .Width = 1000
End With

If you must set more than two or three properties in code, use With, which tells Visual Basic that all objects without an object qualifier are label objects. Without the With keyword, you would have to type the object's name all through the assignments, like this:

lblTitle.Caption = "Accounts Payable"
lblTitle.Alignment = vbRightJustify
lblTitle.Font.Size = 15
lblTitle.Font.Bold = True
lblTitle.Left = 25
lblTitle.Right = 0
lblTitle.Width = 1000

Using Collections and Object Arrays

In earlier lessons you learned about control arrays that you can declare. By declaring an array of five Option Button controls, for example, that all have the same name, you can set property values for one, and all the others gain the same properties. Your application will distinguish between the controls by the control array subscript.

New Term: A collection is a set of all objects of the same data type.

In addition to the control arrays, you can work with collections. A collection differs from an array because your application may contain three command button arrays but only one Controls collection. The Controls collection refers to every control used in your application.

Table 22.2 describes common Visual Basic collections.

Table 22.2. Some of the collections you can manage.
Collection Description
Controls All controls within your application.
Forms All forms within your application.
Printers All printers connected to your system.

The collections support several methods that you can use to manage the collection. Table 22.3 lists some of those methods.

Table 22.3. Some methods you can apply to collections.
Method Description
Add Adds items to collections.
Count Returns the number of items in a collection.
Remove Deletes items from a collection.
Item References a collection element.


NOTE: You can create your own collections, and some of Table 22.3's methods are more useful to you, when you work with your own collections than when you work with the supplied collections. For example, you'd never add an item to the Printers collection because Windows defines that collection from your system's installed printer list.

Suppose that you want to display all controls on the form, even some that might be hidden from other procedures that executed previously. Although you could set each control's Visible property to True, the following loop makes for an easier display of the controls:

For intCtr = 0 to Controls.Count-1
   Controls(intCtr).Visible = True
Next intCtr

The For Each statement makes the loop even simpler. The zero-based collection subscript requires that you loop through the Count-1 subscript, which is a little confusing. Substitute For Each to clarify things and to let Visual Basic take care of the subscripting like this:

Dim ctlControl As Control
For Each ctlControl In Controls
   ctlControl.Visible = True
Next ctlControl

Notice that you must declare a control variable so that the For Each statement has a place to load each control in the collection.

Suppose that you add forms to that same application and you want to make all controls visible on all the forms. The Forms collection makes such a task simple if you use the following nested loop:

Dim ctlControl As Control
Dim frmMyForms As Form
For Each frmMyForms In Forms
   For Each ctlControl In Controls
      ctlControls.Visible = True
   Next ctlControl
Next frmMyForms

If you want to create your own collections, you'll be able to work with them just as you work with the supplied collections. You'll have to declare and manage the collection yourself, but once you build a collection, you can operate on all the collection items more easily than if they were separate or part of a control array.

Given that the Collection keyword is itself a defined object, you can declare a collection like this:

Public colNewCollect As New Collection

If you do not use Dim, but use either Private or Public to declare collections, declare the collections in the general section of a module so that the Public or Private keyword determines the scope (either project- or module-level availability).


WARNING: The previous Public statement declares a new collection class but does not declare any specific members of that collection. To use a collection object, you must not define the specific items to go in the collection.

If you use Dim and declare a new collection inside a procedure, only that procedure has access to the collection. Often, such a local collection is wanted, but be aware that other procedures cannot use the collection.

Once you define the collection in the general section, you then can create the collection's specific instances. Listing 22.1 declares collection members and shows you how to use the methods to add and manage the collection.

Listing 22.1. Creating and managing a collection.

Dim colPeople As New Collection
Dim intCtr As Integer
Dim m As Integer    ` MsgBox() return (not used)

colPeople.Add "George"
colPeople.Add "Sandra"
colPeople.Add "William"
colPeople.Add "Sue"
colPeople.Add "Terry"

` Print the collection
For intCtr = 1 to colPeople.Count
   m = MsgBox("The next name is "; & colPeople(intCtr) )
Next intCtr

` Add another person if you wish
` As you can see, you don't need to
` concern yourself with running past a
` maximum subscript value as you
` would with arrays.
colPeople.Add "Kay"

` The following should display 6 people
m = MsgBox("There are "; Str(colPeople.Count); & _
" in the collection."). 


Here is the output from this code:

The next name is George
The next name is Sandra
The next name is William
The next name is Sue
The next name is Terry
The next name is Kay
There are 6 in the collection.


WARNING: As you can see, a collection's index value begins at 1, not zero, as is the case for arrays and control arrays. The mixture of starting subscripts provides yet another reason for using For Each to step through such items.

The previous discussion shows how you can use the Add method to add new items to the collection. You don't have to worry about a maximum subscript. The problem, however, is that with Add's default method format, you cannot add new collection items except to the end of the collection. In addition, you cannot remove specific items, except for the final collection item, from the collection with Remove.

New Term: A named argument is an argument known by its name and not by its specific position without an argument list.

Add supports a named argument called Before that lets you insert new items into a collection before an existing item. In effect, Visual Basic shifts all the subsequent items down in the list. If you want to add a new name to the beginning of the People collection, code the following:

People.Add "Robert", Before:=1


WARNING: Do not use a regular assignment statement when assigning named argument values, but use the special := named argument assignment operator.

The collection now looks like this:

Robert
The next name is George
Sandra
William
Sue
Terry
Kay

If you want to remove the third name, you can do so like this:

People.Remove 3   ` Deletes the 3rd item

Introduction to OLE Automation

New Term: OLE automation refers to the capability of one application to declare and use ActiveX objects that are actually created by other applications.

As you learned in Hour 21, "Visual Basic and ActiveX," the overall distinction between OLE and ActiveX is getting blurred. Nevertheless, OLE and ActiveX do work well together to support OLE automation. Although this section only scratches the OLE automation surface, you'll probably be surprised at what OLE automation can accomplish.


NOTE: More and more programmers are calling OLE automation active automation due to ActiveX's impact on OLE automation.

Suppose that your application needed to create data files for Excel or Word. Using normal file access routines you learned in Hour 15, "Visual Basic Database Basics," makes such file creation extremely tedious and bug-prone. How can you find the data format required by Word?

With OLE automation your Visual Basic application can actually borrow Excel or Word and, behind the user's back without ever showing the other application, make Excel or Word (or any other OLE automation-compatible application) create the data file for you. When finished, the data file will reside on the disk and no traces of the other application will be left. Your user will believe your application created the data file.


WARNING: Your development computer must have a copy of the OLE automation's application before you can test your application. Also, your user must have a copy of the OLE automation application. Without Word, for example, you cannot use OLE automation to create a Word document.

To create a Word data file using OLE automation, you must first create an object variable that can reference the Word OLE automation application. Declare such an object variable like this:

Public objWordApp As Object


TIP: Always use a global variable for OLE automation objects. The variable references a completely different application outside your application's workspace. Therefore, the variable is truly global to your application's other variables.

objWordApp is an object variable that represents the entire Word OLE automation application. The rest of the code will use this application's reference object variable to perform the data-generation task. Nothing about objWordApp lets Visual Basic know that the object is the Word application, so the following statement will link the option button variable to Word:

Set objWordApp = CreateObject("Word.Application.8")

The 8 is a property that uses Office 97's Word instead of earlier versions. Before Office 97, which technically contains Word version 8, Word used a language called WordBasic for its automation language. Word 8 uses Visual Basic, which is sometimes called Visual Basic for Applications.

Notice that this is not a normal assignment statement. The Set keyword tells Visual Basic not to store a value in objWordApp because the Word application is not a value that you could put into a variable. Set tells Visual Basic to reference the Word application. objWordApp works like a link to Word. Visual Basic will, through OLE automation, transfer functions you apply to objWordApp to the Word application. The CreateObject() function actually starts Word (in the background) and prepares the OLE automation link.


WARNING: If Word is already running, CreateObject() starts another copy of Word. If you want to use the currently running Word, use GetObject() instead of CreateObject() to borrow the running copy of Word. You can test to see if Word is already running like this:

Set objWordApp = GetObject("", "Word.Application.8")
If objWordApp Is Nothing Then   ` True if not running
   Set objWordApp = CreateObject("Word.Application.8")
End If





The null string at the beginning of GetObject()is necessary. If you want to open an existing Word document and work on that document inside Visual Basic, you'll insert the path and filename to that document as the first argument. If you want to use Word to create a new document, leave the null string for the first argument.

Keep in mind that OLE automation is fairly extensive and that you can, through your Visual Basic application, make Word do anything you could do at the keyboard with Word. Therefore, the OLE automation can trigger Word's menus, format text, and save files. You'll apply methods, most of which match Word's menus, to perform these tasks.

Listing 22.2 shows you a complete code set you could use to create a Word document named MyWord.Doc.

Listing 22.2. OLE automation code that uses Word to create a Word document.

` Create a Word document and add text to it
Set objWordApp = GetObject("", "Word.Application.8")
If objWordApp Is Nothing Then   ` True if not running
   Set objWordApp = CreateObject("Word.Application.8")

End If

` Add a document to the collection
objWordApp.Documents.Add

` The title will have a blank line after it
` Move the cursor to the next line (simulate the
` user pressing Enter) by sending the vbCrLf named
` literal to the document
objWordApp.Documents(1).Content.Font.Size = 28
objWordApp.Documents(1).Content.Font.Bold = True
objWordApp.Documents(1).Content.InsertAfter _
      Text:="Why go to Italy?" & vbCrLf & vbCrLf

` The body of the document is next
objWordApp.Documents(1).Range.InsertAfter Text:= _
    "Italy sells the best ice cream in the world." & vbCrLf
objWordApp.Documents(1).Range.InsertAfter Text:= _
    "Italy has the best architecture in the world." & vbCrLf
objWordApp.Documents(1).Range.InsertAfter Text:= _
    "(Oh, and did I mention the ice cream?)"

`Save the document
objWordApp.Documents(1).SaveAs "c:\MyWord.Doc"
` Close the Word document
objWordApp.Documents(1).Close
` Quit the Word application
objWordApp.Quit


WARNING: Listing 22.2 contains a lot of strange-looking properties, events, and methods such as InsertAfter and Range. These are Word-based Visual Basic objects and properties, events, and methods. Although you've not seen most of these properties, events, and methods before, you can probably make a good guess as to what each statement does. (No range is set up by the code, so Range refers to the cursor's current position in the document.)

After running Listing 22.2 (perhaps from an event procedure you tie to a command button), you can open Word and load the MyWord.Doc document created from Listing 22.2. You'll see that the document is fully Word compatible; it should be because Word created it from your application's OLE automation commands. Figure 22.1 shows a Word screen with the document open.

Figure 22.1. The Word document that Visual Basic created with OLE automation.


NOTE: You must be intimately familiar with the OLE automation application before you can work with that application through Visual Basic objects. Often the other application offers online OLE automation support information so you can use that application in an OLE automation setting. You can get help with Word's OLE automation language by starting Visual Basic for Applications from Word's Tools menu and viewing the help files there.

Summary

You now understand more about objects and how to access objects from within Visual Basic. In programming terms, an object is a packaged set of properties and code, and that's exactly what Visual Basic objects such as controls are. You set a control's properties and run methods to manipulate those objects. The object model gives you the ability to pass controls and other objects, test an object's type, and create your own collections that often make programming easier than arrays.

The next hour explains how to prepare your application for distribution now that you've learned how to write powerful applications.

Q&A

Q Why are collections better than arrays?

A
Collections are not better than arrays in all cases. For example, if you need to keep track of 100 integer temperature values, keep those values in an integer array. The array is efficient and you can work with the array using loops as you are used to doing. A collection is nice when you don't know how many items will appear in the group, especially when those items are objects such as controls and not simply regular data types. The collection can grow to any size and the methods you use on the collection make for simple programming because you don't have to keep track of the highest item in the collection yourself.

Q What is the real difference between OLE and OLE automation?

A
OLE lets users edit objects from other applications inside a Form window. The cross-application platforms that OLE provides lets you embed a Paint object in your application without having to code drawing methods that perform as Paint's perform. Before OLE automation, however, regular OLE did not give your Visual Basic application the capability to control the serving application. Applications that support OLE automation can now expose all their internal properties, events, and methods (if they're not OLE automation compatible, they will have no properties, events, or methods) to applications such as Visual Basic. Visual Basic, therefore, can make Access manipulate database tables or make Excel manipulate a named range in a worksheet. Although you must do some extra work on the front end to code the OLE automation, your applications become much more powerful because they borrow technology from these other applications.

Workshop

The quiz questions and exercises are provided for your further understanding. See Appendix C, "Answers," for answers.

Quiz

1. What are three system objects?

2.
What is the difference between a class and an object?

3.
What happens when you use the New keyword inside an object declaration?

4.
True or false: TypeOf is both a statement and a function.

5.
True or false: You can pass objects such as controls and forms as arguments to procedures.

6.
What is the index value for a collection's first item?

7.
How can you insert a new item at the beginning of a collection?

8.
Which OLE automation function should you use to initiate OLE automation when the OLE automation application is already running on the machine?

9.
What is the new term being used more frequently for OLE automation?

10.
True or false: As long as you know the OLE automation language, you don't need the OLE automation application installed on your machine to use OLE automation with that application.

Exercises

1. Write a procedure that decreases the font size of all controls on all forms by 50%. Use a system object to accomplish the change.

2.
If you use Word, Excel, or any other OLE automation-compatible application (as all the Office 97 products are), start that application and search the online help for information on that application's properties, events, and methods used in OLE automation. The more you know about that application's internals, the more easily you can integrate that application and borrow its power for your own applications. If the application is an Office 97 application, search the online help for the Visual Basic help to see how to start Visual Basic. (Visual Basic is often called Visual Basic for Applications in applications' help files. Visual Basic for Applications [or VBA] is the same language as Visual Basic.) Start the application's Visual Basic editor to see a development environment that looks like Visual Basic's own development environment. Open the application's Object Browser to receive an Explorer-like view of that application's properties, events, and methods. Search the Object Browser's online help for extensive OLE automation help.