learning about Class Modules (1 Viewer)

GBalcom

Much to learn!
Local time
Today, 14:01
Joined
Jun 7, 2012
Messages
459
I'm in the process of reading a pretty in depth book on Access VBA Programming (Access 2010 Programmer's Reference by Wrox) and I just read a good amount about Class Modules.

I guess the thing I'm not really understanding yet is their application. The book likened a Class module to a Word or excel template, that you instantiate. (which I though seems like a great example). But the two code examples shown were Classroom student population, and getting a current account balance...

It seems to me (a novice), that these could be easily handled with queries based off of real records in a table. I'm sure the examples are simplified, and their are good practical applications for Class modules...Does anyone have an example their willing to discuss?

Again, I'm trying to learn, so maybe my assumptions above are off based...if so, please tell me.

Thanks!
 

TexanInParis

Registered User.
Local time
Today, 23:01
Joined
Sep 9, 2009
Messages
112
You may not realize it, but you use Class modules all the time! The code modules associated with forms and reports are Class modules. One nice thing you can do with Class modules is declare some of the Module variables and some of the Procedures as Public. This then "exposes" these items as Properties and Methods of the class, respectively. I often like to code a generic close procedure for all forms. If the form is bound, the procedure looks something like this:

Public Sub cmdClose_Click()
' If a record not saved,
If Me.Dirty Then
' Throw it away
Me.Undo
End If
' Close me
DoCmd.Close acForm, Me.Name
End Sub

As implied by the procedure name, the code is also usually associated with the Click event of a command button on the form. But if I want to force a clean close of the form from elsewhere in the app, all I need to do is call this Public procedure as a method of the form's Class module. By default, the name of the Class for any form is Form_formname, so to call this procedure in a form called frmSales, I would do:

Form_frmSales.cmdClose

Pretty cool, huh?

I have also used Class modules as wrappers for things like the Windows Open/Close dialog. Load up a copy of the class, set the options you want as properties of the class, then invoke the dialog by executing a method of the class.

Hope that helps enlighten you...
 

ajvol01

Registered User.
Local time
Today, 17:01
Joined
Dec 12, 2012
Messages
28
You may not realize it, but you use Class modules all the time! The code modules associated with forms and reports are Class modules. One nice thing you can do with Class modules is declare some of the Module variables and some of the Procedures as Public. This then "exposes" these items as Properties and Methods of the class, respectively. I often like to code a generic close procedure for all forms. If the form is bound, the procedure looks something like this:

Public Sub cmdClose_Click()
' If a record not saved,
If Me.Dirty Then
' Throw it away
Me.Undo
End If
' Close me
DoCmd.Close acForm, Me.Name
End Sub

As implied by the procedure name, the code is also usually associated with the Click event of a command button on the form. But if I want to force a clean close of the form from elsewhere in the app, all I need to do is call this Public procedure as a method of the form's Class module. By default, the name of the Class for any form is Form_formname, so to call this procedure in a form called frmSales, I would do:

Form_frmSales.cmdClose

Pretty cool, huh?

I have also used Class modules as wrappers for things like the Windows Open/Close dialog. Load up a copy of the class, set the options you want as properties of the class, then invoke the dialog by executing a method of the class.

Hope that helps enlighten you...

John I really appreciate your explanation - thanks.

I'd also like to learn more about Class modules and how & when to best use them.

Do you have any beginner/intermediate level examples that you could recommend (links) or share (MDB files)?
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 16:01
Joined
Feb 28, 2001
Messages
27,192
A class module is an excuse to tie code to a form or report when that code is specific to the events and actions of the form or report. The OTHER type of module is the general module, which isn't bound to a specific form or report but COULD be used by any of them.

An example from my own activity reporting system:

I have a generic module called StyleAndFormat which contains a bunch of color constants, a bunch of general function and sub procedures, and a lot of PUBLIC entry points for the functions and subs. So if I want to make some of my controls turn white with black background, I call call SetClrByStyle form, control, in-focus (T/F), style-code where the style code is styNormal. If I want it red, I make the same call but with style code styDirty. This is half the battle.

In each form, I have code driven by the GotFocus and LostFocus events which MUST occur in a class module in order to be useful. But each control_GotFocus and control_LostFocus event can call the public subroutines that change control appearance as the user tabs through the controls of the form. (Read up on GotFocus and LostFocus events if you aren't sure.)

Here is where it comes together. Anything that is specific to the form (namely, events for controls on the form) absolutely HAS to be triggered inside the class module of the form - because it is the only thing that can easily take an event trigger. Class modules can call general modules but events cannot directly trigger to general modules. Therefore, you use a class module to handle the intimate events of your form. Reports also have events having to do with group headers, group footers, detail sections, and the form header and footer. In each case, your code - if you needed any - drives things local to the form/report using resources you have defined for common usage in the general module.

Hope that didn't confuse you too much. It's easy once you put it into perspective.

Oh, here's a common question I've seen. When you have a class module, the code for it is not accessible unless the form has been opened. When you have a general module, the code for it is accessible by any form or report or macro (when the macro includes a RunCode action). That's because the code for a class module is intimately bound with the class object (form or report). So intimately bound that if the class object doesn't actually exist in memory, neither does its code.
 

ChrisO

Registered User.
Local time
Tomorrow, 07:01
Joined
Apr 30, 2003
Messages
3,202
I really do not have a meaning of beginner/intermediate but do have some classes broken down into minimalistic form on my SkyDrive in my signature.

It’s a developmental sequence of classes used for ‘drag and drop’ running:-
Drag Drop -> Drag Drop Resize -> Drag Drop Resize GridSnap -> Drag Drop Resize GridSnap Save.

Some end applications for drag and drop, also on my SkyDrive, are:-
Drag Floor Plan, Drag Polygons, Z Order Bound Objects and Drag and Drop Chess.

But I do not know what beginner/intermediate means and can only recommend starting with Drag Drop in the above mentioned sequence.

In general, though, there is very little in code that can only be written one way.
(There may be the exception of passing back system arguments to the system without a class but that is just one possible exception. Let’s ignore that for the moment.)

Overall I see a class as a procedure; it serves the same purpose by reducing the code to one place. It reduces the maintenance of the code to one place and that is the prime consideration.

The next consideration is that the class instance has its own private variables. Those variables are initialised to their default when the class is instantiated. (Let’s try and reduce the gobbledygook here. When we instantiate a class we are making a copy of the class. It is a copy of the class template without the variables in the class being set to any particular non default value. By default, numbers become 0, stings become zero length strings, that sort of thing.)

At the time we instantiate a class (make a copy of the class template) that copy is as dumb as an ox. The real problem is that we don’t even know if the copy is an ox. If the copy of the class template had a variable called NumberOfLegs As Long then the NumberOfLegs would be zero. It would not be appropriate for an ox to have 0 legs else taking it for a walk would become a real drag.

So, for drag and drop, an instance (copy of dumb template) of a class needs variables relating to a specific instance of the dumb ox. The variables therefore define which dumb ox we a talking about.

We can then have properties which set or get the variables of that specific instance of the class. Set Legs to 4 or 0.

We can also have methods which would perform actions on that specific instance of the class. Take the ox for a walk or a drag.

But that’s just my way of looking at it.

Chris.
 

TexanInParis

Registered User.
Local time
Today, 23:01
Joined
Sep 9, 2009
Messages
112
All-

Attached to this message is an excerpt from Chapter 22 of Microsoft Office Access 2003 Inside Out that may help you understand Class Modules better. These are bits and pieces related to Class Module from a reference chapter that may seem a bit disjointed. First, there's a description of the development environment and the fundamental differences between Standard and Class Modules. Next, is a section entitled "Understanding Class Modules" that explains how they work and how you might use them. Finally, I've included various statements that all have something to do with managing Class Modules - Property Get, Property Let, Property Set, Dim, Event, Public, and Private.
 

Attachments

  • ClassModules.zip
    60.5 KB · Views: 148

ChrisO

Registered User.
Local time
Tomorrow, 07:01
Joined
Apr 30, 2003
Messages
3,202
Hi John, and thank you for the attachment.

I may be misreading the intention of this in the attachment:-

>>Use the Optional keyword to declare an argument that isn't required. All optional arguments must be the Variant data type.<<

It is my understanding that all data types can be Optional but it is only the Variant data type which will return True if IsMissing. If a Variant data type is assigned a default value then it too is not IsMissing.

But, as I say, I might be misreading the intention.

Regards,
Chris.
 

Galaxiom

Super Moderator
Staff member
Local time
Tomorrow, 07:01
Joined
Jan 20, 2009
Messages
12,852
By default, the name of the Class for any form is Form_formname, so to call this procedure in a form called frmSales, I would do:

Form_frmSales.cmdClose

Pretty cool, huh?

Sorry but no. That is not the right way to refer to an object. You are referring to the module. Where multiple instances of the object are instanced the reference would be ambiguous.

If the object was not open that expression would create a hidden instance.

The object should be referred to via the Forms Collection (in the case of Forms) or as the explicitly created instance of the object class.

Forms!formname.methodname

objectvariablename.methodname
 

Galaxiom

Super Moderator
Staff member
Local time
Tomorrow, 07:01
Joined
Jan 20, 2009
Messages
12,852
It is my understanding that all data types can be Optional but it is only the Variant data type which will return True if IsMissing.

Yes this is correct.

Other variables wouldn't return True for IsMissing because they have automatic defaults. The string varable is a ZLS, numbers and Dates are zero.

Object variables don't like IsMissing because they don't exist unless a reference is passed so the test throws an error.
 

ChrisO

Registered User.
Local time
Tomorrow, 07:01
Joined
Apr 30, 2003
Messages
3,202
Galaxiom.

>>Object variables don't like IsMissing because they don't exist unless a reference is passed so the test throws an error.<<

An Object should behave like a Long numerical value in that it is initialised to 0.
How did you get it to raise an error using the IsMissing() function?

Chris.
 

TexanInParis

Registered User.
Local time
Today, 23:01
Joined
Sep 9, 2009
Messages
112
ChrisO-

You are correct! I originally wrote that text for Access 97 or maybe 2000. You must declare as Variant if you want to use IsMissing, but that's not required. However, once you use Optional, all successive arguments must also be Optional, and you cannot use ParamArray as the last type.

Galaxiom-

You are correct that using Form_formname will open an instance of the form if it's not already open. By the way, this is the way you get multiple copies of the SAME form open - something that was introduced about Access 2000. I should have mentioned that I use this in a loop that examines currently opened forms. Like this:

Code:
    Dim frm As Form

        ' Close all forms
        For intI = (Forms.Count - 1) To 0 Step -1
            ' Point to the open form
            Set frm = Forms(intI)
            ' Skip me - I'm already closing
            If frm.Name <> Me.Name Then
                ' Execute the form's "cancel" procedure
                frm.cmdCancel_Click
            End If
        Next intI

Rather than set a Form variable, I could have simply done:

Forms(intI).cmdCancel_Click

Don't know why I chose the harder way.
 

ChrisO

Registered User.
Local time
Tomorrow, 07:01
Joined
Apr 30, 2003
Messages
3,202
Thanks, John, I just wanted to make sure we were talking about the same thing.

Chris.
 

TexanInParis

Registered User.
Local time
Today, 23:01
Joined
Sep 9, 2009
Messages
112
Just ran an interesting test:

Code:
Public Sub TestMissing(Optional A As String, Optional B As Integer, Optional C As Variant, Optional D As Object)
    Debug.Print "A " & IsMissing(A)
    Debug.Print "B " & IsMissing(B)
    Debug.Print "C " & IsMissing(C)
    Debug.Print "D " & IsMissing(D)
End Sub

In the Immediate Window:

TestMissing
A False
B False
C True
D False
 

ChrisO

Registered User.
Local time
Tomorrow, 07:01
Joined
Apr 30, 2003
Messages
3,202
D is the curious one:-

Code:
Public Sub TestMissing(Optional A As String, Optional B As Integer, Optional C As Variant, Optional D As Object)

    Debug.Print "A " & IsMissing(A)
    Debug.Print "B " & IsMissing(B)
    Debug.Print "C " & IsMissing(C)
    Debug.Print "D " & IsMissing(D)
    
    Debug.Print
    
    Debug.Print D Is Nothing
    Debug.Print "D value = " & ObjPtr(D)

End Sub

D is Nothing but, since it has a value of 0 it is not Missing.

If D is Set to some Object is has a non zero value, the AddressOf the Object.
If D is Set back to Nothing it has a value of zero.

That leads me to the conclusion that D is actually a Long data type where its value is simply treated differently as an Object pointer; the address of the Object to which it points. It might be stretching things a bit but we can think of Nothing as an Object with an address of zero.

However, we can use the idea of D (above) being a Long. If we take the value of D and store that in a Long then that Long can be passed through OpenArgs. Once on the receiving end of OpenArgs we can take the value in OpenArgs and store it in an Object pointer.

Effectively, then, we can pass an Object through OpenArgs.
It becomes real fun when we pass a Collection Object because that Collection can contain other Objects (pointers to objects).

Perhaps better explained here:-
http://www.access-programmers.co.uk/forums/showthread.php?t=225415

Chris.
 

GBalcom

Much to learn!
Local time
Today, 14:01
Joined
Jun 7, 2012
Messages
459
Wow! Great information here guys! I'll need some time to digest it all...
 

Users who are viewing this thread

Top Bottom