UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
> Creating Classes / Subclassing - Tutorial, Article, Website, Insights For Beg. ?, Any Version    
 
   
ipisors
post Jan 14 2013, 10:50 AM
Post#1


Banned
Posts: 9,239
Joined: 21-June 07



Hi, I am interested in learning more about creating custom VBA classes and subclassing VBA functions. Having perused several pages of Google results without finding articles/sites that seemed right for me to begin, I was wondering if anyone with experience doing same, could point me in a direction. (any and all direct comments on the subject are very welcome too)
I'm wanting a gradual learning curve where first I understand what subclassing/creating custom classes really IS, and secondly the usefulness or when they are appropriate to consider doing, and lastly, how to do them.
Edit - if any comments/tutorials have to do with VB.Net too, that's OK for me, as fairly soon I will be switching over to spend about half my time on Excel/Access programming, but half on VB.NET
Go to the top of the page
 
Start new topic
Replies
jleach
post Jan 15 2013, 09:03 AM
Post#2


UtterAccess Editor
Posts: 10,085
Joined: 7-December 09
From: St Augustine, FL


It's tough to say "when" is the best time to use any of the "more advanced" features that Access/VBA offers... knowing when to use them to a greater benefit comes from knowing how to use them, knowing that the tools are capable of doing XYZ, and knowing when the task is better fitted for XYZ than something else... which, if course, is difficult to know if you don't have a lot of experience with it, so a bit of a catch 22: the more you use them, the more you find places and reasons to use them, but without using them, you really don't know what you could do with them.
For Class modules, there's some straightfoward enough tell-tale signs that they'd be better suited. For example, when you have a module who's sole purpose is to basically do one single (probably large) task, and the coding is getting unruly (although it's difficult to define "unruly"), the code itself may be simplified and easier maintained by going into a class module instead of a standard module.
When you have one module that crunches a lot of code to do one particular task, likely the module only really has one main entry (one public sub/function that's called), usually with a rather long list of arguments, most of which are probably optional, set with a default. So, we have lots of "options" for this particular module, and they're all stuffed into the main calling point of the main function of the module, and it's really kind of ugly to look at when you call the function and see a list of 10 or 20 arguments. Something like this may be a good candidate for a Class module, because you could take all those optional settings (and even the required ones), and turn them into properties, then provide an procedure in the class to process everything that's been previously set. So, you might go to much "cleaner" code, like this:
CODE
'in "loaded-function" form:
lngResult = SomeFunction(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg11:="this", arg19="that")
'if it were in a class:
Dim obj As New SomeClass
With obj
  .property1 = "blah"
  .property2 = "blah"
  .property3 = "blah"
  .property4 = "blah"
  .property5 = "blah"
  .property6 = "blah"
  .property7 = "blah"
  .property8 = "blah"
  .property11 = "blah"
  .property19 = "blah"
  lngResult = .RunMe()
  If obj.Errors <> "" Then Debug.Print obj.Errors
End With
Set obj = Nothing

A major advantage to having direct control over the properties as opposed to a long argument list, is that now you can individually handle each property assignment, such as wrapping with prepatory functions (.property1 = Trim(" SomeString "), where as with a long function call, if you had lots of that type of work to do, you'd have to create variables to hold temporary values, or have an even longer and uglier function call that incorporates all that stuff.
Also, with a Class module in this type of situation, the code itself (the code in the Class), tends to be a lot more organized and maintainable than code which might perform the same task were it all stuffed into a standard module. It's hard to explain how - one of those things that comes with firsthand experience - but one small example is the built in private procedures of Initialize and Termine of all VBA class objects. They run all the time when the class is first instantiated and when it is destroyed, and gives you a place to initialize all of those would-be optional, defaulted arguments, and also a place to clean up any loose ends on the way out, when everything's done. Such initialization and cleanup can be done in a standard module as well, but not nearly so elegantly.
Lebans' ConvertReportToPDF function is a good example, I think, of a standard module long-signature function that could have been more managable in a Class module instead. See the image below:
Attached File  reporttopdf.jpg ( 35.89K )Number of downloads: 14

(not that I have any complaints about this utility! it just serves as a good example). Much nicer would have been a class interface for this instead:
CODE
Dim pdf As New PDFReport
pdf.ReportName = "MyReport"
pdf.OutputPDFFile = "C:\ThisFile.pdf"
pdf.StartViewer = False
pdf.FontEmbedding = True
pdf.CreateReport
Set pdf = Nothing

So, there's a few cases of how class modules can make your codebase a bit more user-friendly. However, it's fair to note here that everything mentioned above can be done with Standard Modules also, if not quite so elegantly.
Here's a case where you want to consider thinking of a Class module, in such a scenario that it might actually make your code safer to run, unlike the above. Let's say you have a standard module, like above, that does many things with more or less one main entry point. Let's say it's really a one-shot deal... you call the function, it crunches a bunch of code, then returns and you're done, but inside that module lets say you have lots of module level private variables that are extremely essential to the operation of the task at hand. These *really* need to be correct, or bad things will happen. Then you start thinking about your overall usage requirements for the task itself, and you ask yourself: what would ever happen if this function somehow got called again, before the original was done running... such as maybe from a timer event or from a query... it's probably not likely, but oh boy would that really make a bad mess of things....
Enter Class modules. Because Classes are instantiated rather than Static (such as a Standard Module), you can create any number of instances of a class and never have any worries that internal variable XYZ might "cross paths" from one instance of the class to another... each instance is self contained. This is why we can open multiple instances of a form (as explained quite nicely by Allen Browne, if you're unfamiliar with how), and each instance can have its own data and the forms won't get confused and accidentally pull data from this other instance instead of the one it's supposed to.
So, here's a case where using a class module gives a real, tangible (in the sense of programming, anyway!) plus over standard modules, rather than just making the code a little nicer to work with. This is most especially true when the Class you're using has a fairly large scope: an instance of it might exist throughout a fairly tall stack of different procedure calls, or maybe even the entire session of the application.
Here's another one that I made great use of... for my forms, I wanted them all to act the same way. Of course, as a novice we put code behind our forms to make standard behavior happen. As we want our applications to look more professional, we end up doing this same thing in most of our forms, and then we've got a lot of duplicate code sitting around in all these different forms. Somewhere around the stage of intermediate, we'll decide to take all those duplicate codes, and put them into a standard module instead, so there's just one copy and each form calls that copy instead of having a bunch of different versions scattered throughout the app. Good work. Now, at some point, you'll run into a case where this function call will require a number of different parameters, and we get what we had in my first example: a huge run of arguments to call the function. Worse though, and the real kicker, is that with one static (standard module) function, you might run into some serious issues if formA and formB get tangled. At the more advanced stage, you say hey, I can make a Class module to handle all this stuff, so the code's all defined in a single place, and then attach that class module to the form so each for has it's own instance....
I'll do something I haven't done to date: dump a bunch of code from the app I've created and maintained for the past 5 or 7 or however many years now (development is stopped - after years, this thing's going to bed, so I don't mind sharing some of the stuff I've horded from it). This won't be usable to you directly, but it'll give you an idea of how I've been using some class modules to help with larger project development.
Attached File  modules.zip ( 15.81K )Number of downloads: 40

Take a look at FOPCore.cls (FormOperations for Core Forms), which handles all the standard behavior of core forms (there's others for subforms, dialogs, popups, etc). Also in there is the code from my template core form. These two work together through event syncing, and having all the standardized core form operations in a class module gets all that code out of the form's module itself, leaving much more room to breath, so to speak.
The Reporter class is just a good example of a complex task that's better managed through a class module rather than a standard module. This Reporter covers all sorts of various options, as you'll see, and handling all this from a standard module would have been an absolute nightmare.
"When" and "Why" are tough questions to answer, without knowing the pros and cons of the tools. Hopefully this will give you a little bit of insight to why, thus allowing you to look at something and help decide whether or not "when" is now.
Also, keep in mind that as far as Class module functionality goes, this really just scratches the surface. Event handling is a huge, huge plus that you can never really emulate with standard modules. The ability to create, raise and listen to an entirely custom set of events is very powerful: beyond the scope of this (already huge) reply. If you get into .NET programming, you'll find out fairly soon - .net will force you to use what we'll call "advanced" event handling much sooner than Access/VBA will.
Anyway, that's enough for now. Hope this helps a bit - stop back with any more questions.
Cheers,
Go to the top of the page
 

Posts in this topic
- ipisors   Creating Classes / Subclassing - Tutorial, Article, Website, Insights For Beg. ?   Jan 14 2013, 10:50 AM
- - BananaRepublic   Maybe this?   Jan 14 2013, 11:14 AM
- - jleach   A Class is a template of an object. There's s...   Jan 14 2013, 12:51 PM
- - BananaRepublic   Jack - FWIW, I've seen people use the term ...   Jan 14 2013, 12:54 PM
- - jleach   Ah, ok... almost the same thing but using events f...   Jan 14 2013, 01:11 PM
- - BananaRepublic   Agreed. I usually don't use it that way but ca...   Jan 14 2013, 01:13 PM
- - ipisors   Thanks much for replies so far. I appreciate it. ...   Jan 14 2013, 01:14 PM
- - jleach   Is there an "actual" term for that? I...   Jan 14 2013, 01:15 PM
- - BananaRepublic   and for OP, here's an example of subclassing i...   Jan 14 2013, 01:15 PM
- - BananaRepublic   When you get right down to it, Access VBA project ...   Jan 14 2013, 01:17 PM
- - jleach   .NET is Class Based, true OOP, yes. Even so much ...   Jan 14 2013, 01:23 PM
- - jleach   Also, FWIW, classes are one of those things that I...   Jan 14 2013, 01:28 PM
- - jleach   Here's another take on it also (one that .net,...   Jan 14 2013, 01:55 PM
- - ipisors   Thanks much for all replies, and taking time to ex...   Jan 14 2013, 02:40 PM
- - jleach   It's tough to say "when" is the best...   Jan 15 2013, 09:03 AM
- - ipisors   For your generously detailed reply, I surely canno...   Jan 15 2013, 09:20 AM
- - jleach   Cool, glad it was able to help. That kind of info...   Jan 15 2013, 11:12 AM
- - theDBguy   Hi Jack, I was about to suggest that... Looking fo...   Jan 15 2013, 11:16 AM
- - bulsatar   Just as an aside, after I got thinking about the b...   Jan 15 2013, 01:54 PM
- - BananaRepublic   Nice. I like how they used images to illustrate th...   Jan 15 2013, 02:12 PM
- - bulsatar   ^ @BR Is that version specific (-2003) or is that ...   Jan 15 2013, 02:24 PM
- - BananaRepublic   No, not version specific - just how VBA editor wor...   Jan 15 2013, 02:27 PM
- - jleach   There's another that allows you to expose the ...   Jan 15 2013, 02:33 PM
- - bulsatar   I did some more searching and, although it isn...   Jan 15 2013, 02:41 PM



Custom Search


RSSSearch   Top   Lo-Fi    15th September 2019 - 09:24 PM