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
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.
|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
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
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.
|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.
|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.
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
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.
` 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")
` 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.
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.
The quiz questions and exercises are provided for your further understanding. See Appendix C, "Answers," for answers.