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

Welcome to UtterAccess! Please ( Login   or   Register )

Custom Search
2 Pages V  1 2 >  (Go to first unread post)
   Reply to this topicStart new topic
> 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
 
BananaRepublic
post Jan 14 2013, 11:14 AM
Post#2


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


Maybe this?
Go to the top of the page
 
jleach
post Jan 14 2013, 12:51 PM
Post#3


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


A Class is a template of an object. There's something in the wiki if you hadn't seen it yet: Classes
If course, jumping into .NET languages or any other OOP language will force you to use them if you want to do ANYTHING, so that's not a bad way to learn.
>> subclassing VBA functions <<
What do you mean by this? Subclassing is a Windows term, the process of intercepting Windows Messages (pumped messages, the things that make everything do everything, basically), doing what you want with them and (optionally) sending them along to their destination (or some other destination you define)... sounds fun!
Anyway, subclassing isn't exactly related to class modules/object programming - two different things that happen to have a similar name.
Cheers,
Go to the top of the page
 
BananaRepublic
post Jan 14 2013, 12:54 PM
Post#4


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


Jack - FWIW, I've seen people use the term 'subclassing' to mean something similar to the process I linked in my previous reply.
Go to the top of the page
 
jleach
post Jan 14 2013, 01:11 PM
Post#5


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


Ah, ok... almost the same thing but using events from another class instead of windows messages (except in VBA class to class, we don't really have much control over flow). Hadn't heard it referred to as subclassing before.
Cheers,
Go to the top of the page
 
BananaRepublic
post Jan 14 2013, 01:13 PM
Post#6


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


Agreed. I usually don't use it that way but can see how the term get used like that -- am sure i've seen that particular usage in other threads / forums.
Go to the top of the page
 
ipisors
post Jan 14 2013, 01:14 PM
Post#7


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



Thanks much for replies so far. I appreciate it. KingMartin told me years ago in Excel forum once, that subclassing was a robust and elegant way to go. At the time I was not ready for it, of course.
ack: Really, even for Visual Basic in .Net framework? when the framework has been built with a "template" of sorts?
Go to the top of the page
 
jleach
post Jan 14 2013, 01:15 PM
Post#8


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


Is there an "actual" term for that? I've always referred to it as Event Syncing, myself.
Go to the top of the page
 
BananaRepublic
post Jan 14 2013, 01:15 PM
Post#9


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


and for OP, here's an example of subclassing in the sense of processing Windows message: http://access.MVPs.org/access/api/api0045.htm
Go to the top of the page
 
BananaRepublic
post Jan 14 2013, 01:17 PM
Post#10


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


When you get right down to it, Access VBA project have classes --- all of your forms and reports are themselves a class. It's just that Access VBA doesn't lend itself to using class as readily. There are also some features that makes classes more valuable in .NET that isn't directly available in VBA.
Odon't have a term for that, sorry.
Go to the top of the page
 
jleach
post Jan 14 2013, 01:23 PM
Post#11


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


.NET is Class Based, true OOP, yes. Even so much as a String datatype is a class... all of them are.
quot;Templates" may not be a good word... a Class is the definition of an object. Look at your screen... all monitors share some properties... a width, a height, a resolution, so a Class, being a representation of an object, might define properties such as Width, Height and Resolution. And a Name... name is common.
So your class - your definition - would like like this. Just a definition, a guideline, if you will:
CODE
Option Compare Database
Option Explicit
Public Height As Integer
Public Width As Integer
Public Resolution As String
Public MonitorName As String

and that's it... in its simplest form, anyway.
Now, because that's just a definition, not the actual object, you need to create an instance of the object. This is how your regular code uses a class object:
CODE
Private Sub MySub
Dim BigScreen As Screen
Dim SmallScreen As Screen
Set BigScreen = New Screen
Set SmallScreen = New Screen
With BigScreen
  .Width = 1920
  .Height = 1080
  .Resolution = "1920x1080"
  .MonitorName = "BigMonitor"
End With
With SmallScreen
  .Width = 800
  .Height = 600
  .Resolution = 800x600
  .MonitorName = "SmallMonitor"
End With
Set BigScreen = Nothing
Set SmallScreen = Nothing

So, that's what I meant by a Class being a template... it's a definition that you use to create instances of your objects: eg - an instance of a monitor that's big, and another that's small, both use the same definition.
.NET is all classes.
Go to the top of the page
 
jleach
post Jan 14 2013, 01:28 PM
Post#12


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


Also, FWIW, classes are one of those things that I just couldn't grasp the concept of, for like, years. Then all of a sudden one day it's like "hey! awesome!" (and they really are), and then from there on out you just "get it". From what I gather, this isn't an uncommon thing to have for people trying to learn classes - I think it comes on a lot of people like that.
ompletely unrelated, but learning a lathe inside and out was like that too... a year of "what is going on" then one day it just all makes sense.
Cheers,
Go to the top of the page
 
jleach
post Jan 14 2013, 01:55 PM
Post#13


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


Here's another take on it also (one that .net, or at least C# and VB.NET, take a good approach to).
Take a look at your tables and the fields defined within them... this is almost the same concept: The table and fields define a template of sorts for the data that will be held within. Each row in the table is a specific instance based on the definition provided by the tables/fields.
This is the same as a basic VBA class. For any given table, you could create a class to match it, and make properties in the class that map to the fields in the table. Then, for each record, you could make a new instance of the class, and apply those record values to the class. Then you would, conceptually, be able to use your data programmatically in VBA within having to use DAO/ADO recordsets.
.NET does this with what's called the Entity Framework (EF). It takes a source database, and creates class objects based on the structure of the tables. It goes so far as to be able to allow you to update the tables simply by changing the properties of the object. Pretty neat, you don't even have to touch the database or an SQL string.
Changing gears a bit, if you're at all familiar with custom Types, they're a bit like a very simplified class module:
CODE
Public Type MYTYPE
  SomeMember As String
  OtherMember As String
End Type
Dim type1 As MYTYPE
type1.SomeMember = "this"
'etc

again, working off the concept of having a definition (the type definition itself), and instances (the variable you create for this specific instance of that type).
Classes are much more versatile than Custom Types though... you can create Methods (eg - functions and subs), events and other things too, where Types can't do any of that (directly, at least).
Cheers,
Go to the top of the page
 
ipisors
post Jan 14 2013, 02:40 PM
Post#14


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



Thanks much for all replies, and taking time to explain things. As I go along I realize more clearly what my question maybe could have been or stated better. I'm basically wanting to get my mind organized around the various categories of coding that is done in VBA that, goes beyond (so to speak), the basic built in VBA functions and libraries.
Is you can see I didn't even know how to properly ask it, but I know that when I see the "really advanced" stuff (such as a portion of what you all--UA experts--contribute to the archive, or such as comes off of Chip or Lebans), I certainly see what I'd consider CUSTOM items. I wasn't sure if it was called custom classes, or custom types, or subclassing, or a bit of all of that. (Not just referring of course to Subs, Functions, etc).
Another way of asking it (this may not be broad enough to cover it, but) is "what is the Class Module used for??" Not having ever used it...
So it sounds like you have sort of addressed these, and more, in various pieces of this discussion. I know how to use the built in object model that comes out of the box, but nothing beyond that like the big dogs do, and I'm wondering what's the best way to get my feet wet in a real life example. I'll get there though, and thanks again for all the help. Will be doing some reading!
Go to the top of the page
 
jleach
post Jan 15 2013, 09:03 AM
Post#15


UtterAccess Editor
Posts: 10,092
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
 
ipisors
post Jan 15 2013, 09:20 AM
Post#16


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



For your generously detailed reply, I surely cannot thank you enough. This helps me immensely more than the platitudes I had been reading elsewhere on the web, such as "classes are robust" and "classes are invaluable".
feel as if I have been given a shot in the arm of knowledge, many thanks to you!
Go to the top of the page
 
jleach
post Jan 15 2013, 11:12 AM
Post#17


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


Cool, glad it was able to help. That kind of information is tough to come across, with so many thousands of generic articles on how to create a class module out there. Tough to explain, but that came out pretty good! I see wiki article in the future for that reply...
Cheers,
Go to the top of the page
 
theDBguy
post Jan 15 2013, 11:16 AM
Post#18


Access Wiki and Forums Moderator
Posts: 76,316
Joined: 19-June 07
From: SunnySandyEggo


Hi Jack,
I was about to suggest that... Looking forward to reading it...
C
Go to the top of the page
 
bulsatar
post Jan 15 2013, 01:54 PM
Post#19



Posts: 1,208
Joined: 16-June 10
From: Indiana, USA


Just as an aside, after I got thinking about the benefits I also started thinking about how to handle multiple instances (array, variables, collections, etc.) and it might also be helpful to tie in a typed collections example. I searched the web and found one that I understand in wording and usage so thought it would help others:
http://www.wiseowl.co.UK/blog/s239/collections.htm
Go to the top of the page
 
BananaRepublic
post Jan 15 2013, 02:12 PM
Post#20


Dungeon Cleaner
Posts: 1,520
Joined: 16-June 07
From: Banana Republic


Nice. I like how they used images to illustrate the point.
Just to point out, that they didn't mention that you can enable For Each looping on your custom collection by creating a NewEnum function:
CODE
Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
  Set NewEnum = myPrivateCollection.[_NewEnum]
End Function

Note that in order to import this, you have to export your class out as a .cls file, paste the function (and change the "myPrivateCollection" to whatever name you're using for your class's collection variable), save the change, then import it back in VBA. You cannot simply paste the Attribute instruction directly in VBA editor.
You can also use the approach to specify Item member as default by setting another attribute:
CODE
Attribute Value.VB_UserMemId = 0
Go to the top of the page
 
2 Pages V  1 2 >


Custom Search


RSSSearch   Top   Lo-Fi    20th September 2019 - 01:45 PM