[AccessD] Doing some thing the class way... was Toolbar

John Colby jwcolby at gmail.com
Sat Jan 29 07:57:09 CST 2022


Bill,

If I create my own class to "wrap" an object, I have to dimension a
variable to hold a pointer to my class after I open it.  Let's assume I
want to create a clsFrm to wrap my form and sink events from my form.

1) I create my clsFrm.
2) In the header of my clsFrm I create a variable

dim frm as form

3) I create an Init function

function finit(lfrm as form)
   set frm = lfrm
end function

Back in the header of my form's cbf module I dim a pointer to my class

dim gclsFrm as clsFrm

In The OnOpen of my form I instantiate my class

function form_OnOpen()




On Sat, Jan 29, 2022 at 7:38 AM Bill Benson <bensonforums at gmail.com> wrote:

> John - I need to ask for clarification on a few definitions and procedures
> in your explanation.
>
> 1. What does CBF stand for?
> 2. Where and how do you create instances of the class module you are
> assigning forms to?
>
> I have a new database with only one form named Form1, which has no code in
> its code module, and which has had added to it, in design view before I
> closed and saved it, a single control (command button) named Command0. I
> will next write some code in a class module I named clsForm, and a
> procedure named LoadForms in a standard module named Module1; I will single
> step through LoadForms and report on intermediary results. As I will hit a
> runtime error very quickly, I will ask you some questions.
>
> 'clsForm
> Option Compare Database
> Option Explicit
> Public WithEvents MyForm As Form
>    Private Sub MyForm_Load()
>        g_i_IncrementForms = g_i_IncrementForms + 1
>        MsgBox "Instance " & g_i_IncrementForms & " of Form_" &
> Me.MyForm.Name & " was unloaded"
>    End Sub
>
>    Private Sub MyForm_Unload(Cancel As Integer)
>        MsgBox "Instance " & g_i_IncrementForms & " of Form_" &
> Me.MyForm.Name & " was unloaded"
>    End Sub
>
> 'Module1
> Option Compare Database
> Option Explicit
> Public g_i_IncrementForms   As Long
> Public g_col_Forms          As Collection
> Sub LoadForms()
>    Dim clsForm     As clsForm
>    Dim Form        As Object
>    Dim Forms       As Object
>
>    Set Forms = Application.CurrentProject.AllForms
>    For Each Form In Forms
>       Set clsForm = New clsForm
>       g_i_IncrementForms = 0
>       Set clsForm.MyForm = Form
>       If g_col_Forms Is Nothing Then
>         Set g_col_Forms = New Collection
>       End If
>       g_col_Forms.Add clsForm
>    Next
> End Sub
>
> Single-Stepping through Module1.LoadForms: Before the line Set
> clsForm.MyForm = Form, the immediate window can give me these results:
>    ?TypeName(Forms)
>      AllObjects
>    ?TypeOf Forms is AllForms
>      True
>    ?TypeOf Form is Object
>      True
>    ?TypeOf Form is Form
>      False
>    ?Forms(0).name
>      Form1
>
> Some things to note:
>     In the construction above, Form is declared as Object.
>     The line Set clsForm.MyForm = Form, will throw a runtime error.
>
> If instead this declaration had been used
>    Dim Form        As Form
>
> then this line would have produced a runtime error:
>    For Each Form In Forms
>
> Therefore, in order to have some kind of collection to loop *prior* to
> opening any forms, I have to deal with the AllObjects class with members of
> type Object. Declaring the MyForm object in the clsForm class module is
> what causes the assignment  Set clsForm.MyForm = Form to result in a type
> mismatch error.
>
> So given my results, I concluded - you will apparently tell me WRONGLY -
> that using class modules to house a Form's events was not possible until
> the Form itself has been opened.
>
> So in order for me to understand what you are implying by stating the class
> module approach can be used to hold the Form's events, I need you to show
> me some code that will create an instance of clsForm for each Form type
> access object. That will enable me to apply your methods. Your explanation
> so far confuses me, since you talk about declaring things "in the Form
> header". What Form header, in the code module of the Form? If that is so,
> then the Form has to be opened in order for those objects to get assigned
> something in memory. Until them, I assume they are either allocated some
> memory, or are in fact nothing at all, prior to a particular Form opening.
>
>
> On Fri, Jan 28, 2022 at 9:44 PM John Colby <jwcolby at gmail.com> wrote:
>
> > Bill, I am in no way dissing your answer, your experience, or point of
> view
> > - in fact I highly respect all of the above.
> >
> > The original author asked if it could be done in a class called from each
> > form that wanted to do this.  Seems like that is worthy of asking, worthy
> > of consideration.
> >
> > There are more ways to kill a cat than choking it to death on butter as
> my
> > mamma used to say.  Sometimes quick is good or even best.  I wasn't even
> > really addressing the original thread since I wasn't following it
> closely.
> > I was addressing the concepts.
> >
> > I understand quite well that to the majority of Access developers what I
> do
> > with classes is, shall we say, not understood well, if even at all.  I
> try
> > occasionally to poke ideas into conversations just to stimulate thinking
> > about how we do things. So...
> >
> > Frameworks are everywhere.  In the 80s I learned to program in Turbo
> > Pascal, whereupon I stumbled on their database framework.  It was a
> SYSTEM
> > of code which allowed me to use a database for Turbo Pascal.  From that
> > experience and others a little later grew my passion for creating my own
> > framework for Access, office and VBA.
> >
> > Using a class to wrap a form is the foundation for a framework.  Using a
> > class to wrap each control is another piece of that framework.  I wrote
> > every single piece of my framework as code behind form, calling functions
> > in a library of functions, because where else does code go?
> >
> > It didn't take long to discover that I was coding a concept over and over
> > in many of my forms.  And my CBF was looooonnnnnnngggggg.  Out the door
> and
> > down the hall loooonnnnnnnggggg..... because I was sinking events in each
> > form, doing exactly the same thing in form A as in form B.  Except I was
> > embedding the event sinks to do that in each form.  Identical code,
> > everywhere.  A maintenance nightmare.  And I ran square into that
> > maintenance nightmare myself.
> >
> > When I discovered classes and the fact that I could write a clsFrm, wrap
> my
> > form with my clsFrom and then sink form events into that clsFrm, all of a
> > sudden all of those event sinks in all those CBF modules doing exactly
> the
> > same thing went away.  Any code that was used everywhere went into my
> > clsFrm and those events that used to be sunk in the CBF of all those
> forms
> > was now sunk in my clsFrm.  Except that I was still sinking events for
> > other objects directly in my clsFrm.  IOW modeling more than one thing in
> > my class.
> >
> > CAUTION... In OOP, one of the foundational ideas is that an object models
> > one thing (or a system).  A clsFrm models a form, a clsCbo models a combo
> > box etc.  If I think about the CBF module behind a form, it is instantly
> > obvious that I am writing a class which models a form, AND EVERY combo,
> > text box, radio button etc placed onto that form.  NOT GOOD!!!
> >
> > Convenient yes.  It allows us as nube programmers to get our feet wet
> > writing event sinks, to learn event driven programming, to learn about
> the
> > dozens of events for the dozens of controls, but hey... what a friggin
> mess
> > we make as a result.  Microsoft did us all a favor with the CBF module
> > behind forms, making all that "event sinking" stuff easy precisely so
> that
> > we would learn it.  But... MSFT expects us to learn that stuff and then
> > think about moving on.
> >
> > It isn't like I never did that CBF thing, I did!  For the first 10 years,
> > the entire decade of the nineties I did exactly that.  Forms with dozens
> of
> > controls embedded in them, with any events for any of those controls sunk
> > directly in the CBF class module.  Code out the door and down the hall in
> > every form.  There is a better way.
> >
> > Not a faster way, not more convenient in any given situation, not even
> > appropriate in every given situation, but fundamentally better from an
> OOP
> > perspective.   If the same code is in events in many forms, move those
> > events into a clsFrm and have them written in one place.  Reference the
> > class in the CBF and pass in a pointer to the form.  Sink those events in
> > clsFrm now.  Voila, all that repetitive code in all those CBF modules is
> > gone.  Which makes my code much more readable, much more maintainable.
> >
> > We can have a conversation about frameworks if we want.  We can discuss
> how
> > it is done, why it is good, when it is and isn't useful.  What we can't
> do
> > is discuss is how doing xyz is always better, because that isn't true.
> >
> > In this specific case, the toolbar thingie, it may not even work to try
> and
> > do it from a class.  TBH I didn't even look or think about it.  I was
> > addressing "can it be done" not "is that the best way".
> >
> > --
> > John W. Colby
> > Colby Consulting
> > --
> > AccessD mailing list
> > AccessD at databaseadvisors.com
> > https://databaseadvisors.com/mailman/listinfo/accessd
> > Website: http://www.databaseadvisors.com
> >
> --
> AccessD mailing list
> AccessD at databaseadvisors.com
> https://databaseadvisors.com/mailman/listinfo/accessd
> Website: http://www.databaseadvisors.com
>


-- 
John W. Colby
Colby Consulting


More information about the AccessD mailing list