I’m going to attempt to explain what this app does and explain classes as I go. I apologize in advance for the parts of this tutorial that might be confusing, because I was in a hurry while writing it. I intend to go back and edit/rewrite it, but who knows if I will ever get around to it.
Try to think of each of the classes as a DLL as I explain things. The only difference is that its part of your project instead of being references by your project. (In reality most DLLs ARE simply classes, and only a few of them have anything other than classes in them).
The other thing to keep in mind when making (and thinking about) classes is that they need to be completely abstract from the rest of your program. I didn’t know this when I first started using them and I would often reference my Form directly from my class, which is a bad thing. While you are making the class, always pretend that ANYONE could be using it in the future and that they might not have a frmMain in their project or anything like yours. Rule of thumb: Your class should be completely unaware of anything else in your project (except, possibly, of other classes).
Also, I used the “Class Builder Utility” Add-In that comes with VB to make this example. It speeds up the process a lot, but doesn’t name the variables the way I like so I don’t use it that often. If you don’t already have it listed in the Add-Ins menu then go to “Add-Ins > Add-In Manager > Class Builder Utility”.
One other thing I want to mention is the definition of a method. I never knew what this was for a long time and I doubt everyone reading this does. A method basically includes Functions and Subs. So when ever I use that term I mean either a function or sub.
Okay, Here we go…
How properties work
Simple properties work almost exactly like Functions and Subs do. There are 3 kinds of properties:
- Public Property Get MyProp() As String
- MyProp = m_sMyProp
- End Property
Property Get is the most like a Function. This method is called whenever the value is being retrieved from the property (IE – “a = MyClass.MyProp” or “CurrentHP = mcChar.HP”). You simply return a value using the name of the property. In the example above, m_sMyProp is a modular level variable that holds that value of that variable. You don’t have to return a modular level variable. You could (for example) return the UBound() of an array or you could make a lot of calculations based on other information in the Class and then return that number.
- Public Property Let MyProp(ByVal NewData As String)
- MyProp = m_sMyProp
- End Property
Property Let is most like a Sub and is called whenever you assign a value to a property (IE – “MyClass.MyProp = “fluffy bunnies”” or “mcChar.HP = 100”). The value inside the parenthesis is the value that was assigned. In the example I just mentioned, NewData would have the value “fluffy bunnies”. What you decide to do with the new data is up to you. Most of the time it will be stored back into a modular level variable and used later.
This is the same as Let, but used with objects and things that require you to use the Set keyword.
One thing I should note is that you can chose whether or not to include Get, Let or both. Only having a Property Get means that property is read-only. Having only a Property Let means that property is write-only. Also note, that to make one property readable and writable, you must have both statement methods and they must have the same name (MyProp in this case).
The only time you would have all 3 is when the data type is a variant because it could be a simple data type, (string, long, etc) in which case Property Let would be called, OR it could be an object, in which case Property Set would be called.
I still have trouble remembering which one is which so I wrote myself a sticky not that says “Get – Returns an internally stored value” and “Let – Accepts a new value”.
A collection is the same as a class, but is called a collection because it acts as a container for another class. In this project cItems is a collection of the cItem class. You can think of a Collection as an array on steroids. A typical collection has the following properties and methods:
Add: Adds a new item to the collection and usually sets some of the common properties. Since these properties are usually just modular level variables, they can be set form anywhere inside the class. In this case, they are being set inside the “Add” method.
One method that is commonly set here is the items “Key”. The key is a method of accessing the items in the collection without their index number. You can use a string instead.
The Add method also return an instance of the class that was just created. The reason is because you have the option of doing something like this: (inside the form, not inside the class) “Set cCurrentItem = cRm.Floor.Add(Gold, 100, 10)” and then “cCurrentItem.Value = 50”.
Item: This method returns an instance of the class that is being held by the collection. In this case the class would be cItem (cItem being an in-game item and not an item in the collection). the Item method of the collection takes a variant argument. This variant can either be the items Key or its index number.
Count; The number of items in the collection.
Remove: Removes the specified item in the collection. Takes a variant as an argument which represents either the index or key of the item you want to remove.
Set mcChar = New cCharacter: Here we use the “Set” keyword (not property type) to make a new instance of our classes. We have to use “Set” because the variable is not a standard data type (Long, String, etc). When we create a “New” instance of the class, the Class_Initialize event is fired inside the class. Inside the Class_Initialize event of both cCharacter and cRoom there is code that Sets a new instance of the Items collection (collections are also classes). We’ll get to collections in a minute.
Also note that mcGame and mcChar are modular-level (Form-level) variables and cRm is a local variable. This is because we only need cRm inside this sub, and the other 2 are used throughout the program.
Call cRm.Floor.Add(Gold, 100, 10) Let’s walk through what is happening here:
1) cRm: returns that instance of the cRoom class
2) Floor: returns a Collection (named cItems). Right here the “Property Get Floors()” method is being called. NOTE: cItems is a Collection and cItem is a class.
3) Add: this is a method of the cItems Collection and since that is what we just referenced in the last step, that is what we have access to. This time the “Public Function Add()” function is being called. Inside that function, some of the properties are being set in there and then a cItem class is returned. Also, note that inside the Add Function a new cItem was created. That means that the Class_Initialize event was raised inside cItem (although there is nothing in it in our example).
Enum:One other thing worth mentioning on the “Call cRm.Floor.Add(Gold, 100, 10)” line is the use of “Gold”. Inside the cItem class is an Enum. Incase you don’t know, an Enum (Enumeration) allows you to assign names to numbers. It is better than using a String to hold “Gold” because strings are slow. The other advantage is that the user gets a pop up menu of all the possible values for that Enum. This is the same as declaring: “eVar As VbMsgBoxResult”. When you type “eVar =” in VB6 you get a drop down with all the possible values for that variable. In reality eVar is just an Integer or Long data type, but declaring it as VbMsgBoxResult adds ease of use while programming.
Set cBadGuy = New cEnemy: Create a new instance of the cEnemy class and call it cBadGuy. The Class_Initialize event of cEnemy is being fired here.
cBadGuy.Difficulty = 40: Assign a difficulty level to the enemy. Here the Property Let method is being called because we are assigning a new value to the property.
bCharacterWon = mcGame.Duel(mcChar, cBadGuy): This calls the Duel method inside the cEngine class. It accepts a cCharacter and a cEnemy class as parameters.
Inside the function we raise an event called “DuelStart” and pass a local variable “bCancel”. Read the next section to learn more about events.
If bCancel is False after the event, then we go ahead an proceed with the duel. There is not code for it, but we have both the objects we need. We could use the .Level property of the Character and the .Difficulty level of the to take random amounts of damage away from each player.
To add an event to your class, all you need to do is add a line with this format to the General Declarations section (next to your modular level variables): “Public Event MyEvent(ByVal Argument1 As DataType, ByVal Argument2 As DataType)”. You can also use ByRef for the arguments that we want the user to be able to change (even though we will often be the only user).
To make the events available to the form that is implementing the class, you have to use the WithEvents keyword. Inside your form you should have a line that looks like this “Private WithEvents cTestClass As cMyClass”
In the example class we use the “DuelStart” event to show when a duel has started (obviously ). In the declarations section of the cEngine class, we have this line “Public Event StartDuel(Cancel As Boolean)”. That is the declaration of the variable.
All we have to do to raise the event is…VB Code:
- Dim bCancel As Boolean
- RaiseEvent StartDuel(bCancel)
We can raise this event from anywhere in class that is appropriate. A local variable is passed ByRef because we want the user to be able to change the value of the variable and we need to know whether to continue with the duel or not.
Using properties and events in Forms: Everything discussed here can applied towards normal forms (and User Controls). You can add properties and events to your Form the exact same way we did in this class example. This is especially useful when making a small form in your program that acts like a dialog:VB Code:
- Dim f As frmAbout
- Set f = New frmAbout
- Load f
- ‘ Set some variables before showing
- f.UserName = “Joe”
- ‘ Show the form
- f.Show vbModal, Me
- ‘ Use the variable that would have changed while
- ‘ the form was open.
- cmdExit.Caption = “Goodbye ” & f.UserName
- Unload f
The reason we can apply all the same things to a form is because a Form IS a Class. Just think about it, forms have properties, events and methods just like a class.
Thanks for taking the time to read this tutorial/example. If you spotted any errors please feel free to PM me because I know there are some in there (considering I wrote this in a rush ). If you have any suggestions let me know, also. Or if you just liked it you can drop me a line. People also like to know when their work is appreciated .
I hope you enjoyed this venture into some of the aspects of Object Oriented Programming in VB6.
Nice beginner tutorial on classes EyeR, I just would like to make a couple of comments if I may. You stated that a method is either a Sub or a Function which is basically correct however only a Public Sub/Function will be a method. A Private Sub or Function is not considered to be a method since it can’t be called from the outer world (from anywhere except from inside the class).
There is also possible to have a method or property declared as a Friend (instead of Private or Public). This will only be useful if you would create a component like an ActiveX DLL/EXE or an ActiveX Control. A Friend can only be called from modules (classes, usercontrols, Forms, or regular BAS modules) that belongs to the same project and not by projects that reference the component. It’s also allowed to have for example Property Get declared as public and Property Let declared as Friend, which means that from the outer world (the project that reference the compiled DLL or OCX) the property will be read-only, while still allowing other classes (or other modules) inside the same project change the property value. So for example a collection class could be able to write to a property value of the contained objects while a project referencing the collection only can read the property value.