[AccessD] Your favorite control behavior

John W. Colby jwcolby at colbyconsulting.com
Sun Mar 7 20:31:52 CST 2004


>When it comes to subform tabbing you can store the tab index
(me.parent.tabindex), do a one time write of cursor navigation code for the
subform (for continuous forms for example) and at EOF, iterate the parent's
control's tab index properties and set focus to the next one so the user
doesn't know he was ever in a subform.

Sounds like one for the framework!  Thanks.

>Accelerator keys on the labels were an adjunct in the past before I found a
really friendly tab order navigation approach for subforms and was fine for
users who worked with an application for more than a few weeks.

Yes, they are very useful and I use them a lot in my applications .

>Now many depend on the Accelerators that Access doesn't give you unless you
code them, but tabbing in and out of subforms is handled in a transparent
manner.

I'll try and figure out what you are talking about.  It would be handy to
have this.

>Standard functions to change display on or off focus don't require search
and replace.

Any call to a function that is stored directly in a control property
requires a search and replace tool to find where it is used.  If I am
writing code and want to find them, and they are in event stubs - in a class
or directly in the form - I can just use the binoculars.  If they are in
control properties I can't do that.  That is disruptive to my work method.

>If there's a control that can get focus, the handler is there, always.

As it is in my framework.

>If the control is disabled, it doesn't fire.

Likewise in my framework.

>You can also leave in your own search and replace in a development copy of
an mdb and document the usage of property sheet function calls.

I document these things in a central code repository where all code for a
given type of control is stored... the control's class.

>The function is aware of the control, if screen.activecontrol is passed and
the function can be as aware as WithEvents processing that control A
requires one kind of processing and control B another, and you can also pass
additional parameters if the function is to provide selective functionality.

Of course.  But then again in order to change what a given control does you
have to go in to the property on that control and do stuff...  To change a
hundred controls on two dozen forms requires a LOT of hunting and searching.
Does this combo on this form use that?  Yep.  How about this one on that
form... nope.  This one?  Yep.  That one...  OK, break out the Find and
replace and sit there looking at each one to decide...

Remember, I've done all that stuff, and I choose not to.  I know exactly
what you are up to, I used that method for about 6 years until a better
(IMHO) tool came along.  No, I stopped hooking up events directly to code
LONG before that but I was still just calling functions in libraries (from
event stubs in the form's class).  That works.  In fact I built an entire
wizard to insert event hooks to call my functions at the tap of a hot key.
Been there, cone that, never go back!

>I don't know for a fact, but I would suspect there are 20 'developers' who
understand the function call that I use to every 1 who could just start
working with your framework.

I'd bet the ratio was a bit closer to 10,000 to one.  On the other hand I'd
bet that about 10,000 times as many people could feed and groom a horse as
could fix their car.  And I've seen some of your code as well Jurgen, it
caused MY eyes to cross (and I'm no lightweight when it comes to code).

>I'm coming to depend more on WithEvents, especially as I move into other
programming languages, but I still find it quicker and less code and easier
for most 'developers', like the kind you meet at a local Access users group,
to understand the way I've been doing it rather than to understand a
particular implementation of someone's framework.

Of that I have no doubt.  I have frequented many users groups, and to put
"developers" in quotes is entirely reasonable.  Whether I used a framework
or not, I doubt that many of those "developers" are capable of maintaining
my (or your) work.  That is no reason not to use a framework.

You see, the thing is that with a framework, making a form do (generic)
things is a few lines of code in the form's OnOpen.  Open any of my forms,
and you can just read what is being hooked up.  I don't spend any time at
all getting not in lists going, nor dependent combos, nor JIT subforms, data
validation, filtered recordsets, and the dozens of other behaviors that my
framework provides.

When you build a form you have to define the form's recordset.  You have to
get specific controls on the form and arrange them.  You have to do the
design work of THAT form.  My framework doesn't eliminate any of that, I
still have to do that.  Once I have that done, I just add a few lines of
code in the OnOpen to set up specific control behaviors that need
parameters.  If you walk in to my shop because I was killed by a bus and
can't figure out my framework, you can just delete a few lines of code and
all that stuff goes away and you can tie in your own.  There's nothing
magical about what I am doing.  My NotInList looks pretty much like yours,
it's just that mine is embedded in my framework and I don't have to cut and
paste controls from somewhere to get it.  A line of code passing the table /
field / form and that control has that functionality turned on.  Without it,
the functionality is turned off.  Take out the class init stuff entirely and
THAT form loses all of the framework's functionality.  How do I go about
stripping it our of your form when I take over your stuff and hate what you
are doing?  I know the answer because I have taken over systems with the
function calls embedded in control properties.  The answer is NOT PRETTY!  I
was finding function calls in properties for YEARS afterwards.

To each his own, and you obviously are happy with what you are doing.  I do
not like that way of doing things, I have done it that way, I stopped doing
it that way, and I will never go back to doing it that way.  And when I have
to maintain a system where that method was used, my price goes up!

John W. Colby
www.ColbyConsulting.com

-----Original Message-----
From: accessd-bounces at databaseadvisors.com
[mailto:accessd-bounces at databaseadvisors.com]On Behalf Of Jürgen Welz
Sent: Sunday, March 07, 2004 11:58 AM
To: accessd at databaseadvisors.com
Subject: RE: [AccessD] Your favorite control behavior


When it comes to subform tabbing you can store the tab index
(me.parent.tabindex), do a one time write of cursor navigation code for the
subform (for continuous forms for example) and at EOF, iterate the parent's
control's tab index properties and set focus to the next one so the user
doesn't know he was ever in a subform.  Accellerator keys on the labels were
an adjunct in the past before I found a really friendly tab order navigation
approach for subforms and was fine for users who worked with an application
for more than a few weeks.  Now many depend on the Accellerators that Access
doesn't give you unless you code them, but tabbing in and out of subforms is
handled in a transparent manner.

Standard functions to change display on or off focus don't require search
and replace.  If there's a control that can get focus, the handler is there,
always.  If the control is disabled, it doesn't fire.  You can also leave in
your own search and replace in a development copy of an mdb and document the
usage of property sheet function calls.  The function is aware of the
control, if screen.activecontrol is passed and the function can be as aware
as WithEvents processing that control A requires one kind of processing and
control B another, and you can also pass additional parameters if the
function is to provide selective functionality.  As a general rule, I do not
add such additional functionality to fundamental events such as focus.  For
control arrays such as grids on custom calendar or calculator forms, I find
it helpful to hookup the controls by passing in a number that represents the
controls position in a grid.  For example, a calendar may have 42 labels
with mouse click, cursor movement and keyboard navigation events.  In a case
like this, the controls are in an array of controls in the code behiind the
form, lblCal(0 To 41), and the functions are passed the number value of the
control (or screen.active control and the number is parsed from the name).
In this manner, there is a single event procedure that handles all the
buttons or labels for all the controls in the grid.  I don't know for a
fact, but I would suspect there are 20 'developers' who understand the
function call that I use to every 1 who could just start working with your
framework.  I believe that a client who had to find a developer to take over
my application would have very little difficulty finding a replacement for
me.

I was unsuccessful in using WithEvents to process NotInList in a manner that
worked for me.  There is not a great deal of multi field parsing involved in
my approach.  I'll parse names for example, and set a few default values
that the user may change.  Using single record bound recordsets for a form
that displays the kind of record being added, there is no need to change
data entry mode because the record is immediately created in the event and
the form is navigated to the record for completion.  Alternatively, a user
can enter a contact from various forms that require an associated contact
and often it is enough for an application to have a name when the context
from which he was added signifies the kind of contact, the company for which
he works and the record to which he is associated.  I allow the users to
choose to add additional information but it often isn't necessary nor is
additional information always required or available.

I'm coming to depend more on WithEvents, especially as I move into other
programming languages, but I still find it quicker and less code and easier
for most 'developers', like the kind you meet at a local Access users group,
to understand the way I've been doing it rather than to understand a
particular implementation of someone's framework.

Ciao
Jürgen Welz
Edmonton, Alberta
jwelz at hotmail.com





>From: "John W. Colby" <jwcolby at colbyconsulting.com>
>
> >That is almost exactly the way my Notinlist procedure is coded.  I also
>add
>two parameters, one for the target table to which the record will be added
>and one for a user name for the type of data to be added.
>
>My framework has this functionality built in.  The developer programs the
>framework for each such control in the form's OnOpen with syntax like:
>
>     With fclsfrm.Children
>         .Item("cboIDCity").NotInListData "tlkpCity", "CI_Name", "lfrmCity"
>         .Item("cboIDPrefix").NotInListData "tlkpPrefix", "PFX_Prefix",
>"lfrmPrefix"
>         .Item("cboIDSuffix").NotInListData "tlkpSuffix", "SFX_Suffix",
>"lfrmSuffix"
>         .Item("cboIDCity").DependentSet
>fclsfrm.Children("cboIDContactCity")
>         .Item("cboIDST").DblClickFormData = "lfrmState"
>         .Item("cboIDContactCity").NotInListData "tlkpCity", "CI_Name",
>"lfrmCity"
>         .Item("cboIDContactSt").DblClickFormData = "lfrmState"
>         .Item("cboIDContactCity").DependentSet
>fclsfrm.Children("cboIDCity")
>     End With
>
>This is actual code taken from the Open of a form in an application.  You
>can also see the calls to set up "dependent object processing" for combos
>that have other combos that need requerying when they are changed.
>
>For the NotInList processing, as you can see I specify the combo name to
>find the class for in a collection of classes - .Item("cboIDCity"), then
>specify a method of that class that I will pass parameters into -
>.NotInListData, then pass in the table name, field name, and a form to open
>if the double click is used.  If the form is missing, the double click is
>disabled.  If the table and field are missing but the form is there, then
>the NotInList is disabled.  There are tables that a combo can display data
>from that have multiple fields that may need editing.
>
>In addition, my code that opens the form takes the PK of the item currently
>selected and looks up that record, so that when the form opens it is
>already
>on that record waiting to be edited.
>
> >I just set a single record recordset for the existing form to the record
>that is added and it displays the new data in the appropriate field or
>fields.
>
>I tried doing multi-field parsing and such and it just got too messy and
>confusing to the user.  If the table has multiple fields, I open an edit
>form, take the data the user just typed that wasn't in list and make that
>data the "default value" of the control on the form for the data displayed
>in the combo.  For example if the user is typing in an SSN of a person ad
>it
>is not in list, there are waaaay to many fields to fill in for a new person
>to just do it without a form, so I open the form in Add mode, and place
>that
>SSN in the ssn field on the form.
>
>This is all done using the combo control class communicating with the form
>class.  The control class opens the new form and passes in OpenArgs.  The
>form class discovers it has openargs, loads an OpenArgs class which parses
>the OpenArgs and processes any standard OpenArgs such as the one to find
>the
>control and make the data the DefaultValue.
>
> >in the On Got Focus entry in the property you could enter:
>=OnFocus([Screen].[Activecontrol])
>
>Unfortunately doing things that way has several major drawbacks.
>
>1) You can't use the Find in a code module to find everywhere that function
>is called since the call to the function isn't in code.  I realize that it
>can be found from a search utility such as speedferret or Find and Replace
>but that means that you now have to switch focus and go to that utility.
>
>2) You can't add other functionality to that event since you are specifying
>that YOUR function be called.  There is no generic event stub for adding
>additional processing to.
>
>3) Programs such as my framework which need to hook events just write
>MyCtl.SomeEvent = "[EventProcedure]" in order to hook the event and cause
>Access to route processing to the event stub.  Your custom processing would
>just disappear now.
>
>Using this method is fine if you are the only developer who will ever touch
>your app (and unfortunately many developers simply don't care about the guy
>that comes along behind).  You know you do that, you love doing that and
>you
>are happy with it.  God forbid you get hit by a bus and I have to take over
>maintenance of your app because I will be cursing your name for the rest of
>the life of that application (or until I get the mess straightened out).
>
> >Another nice means to hookup events automatically is to create a control
>combination, or even a single control, encapsulated on a sub form all by
>itself.
>
>My only problem with using subforms in this manner is the frustration of
>getting the cursor movement to work correctly.  The user is tabbing along
>filling in data and hits a subform and has to then use special keys to get
>out of the thing and into the next control to be filled in.  A custom class
>that has all the required processing that your form class has gives me all
>(most) of the advantages that you mention without the "cursor movement"
>issues since the control is now in my main form.  The only thing I don't
>get
>is the "drag and drop and I'm done".  I do have to dimension the class,
>initialize it, and clean it up when I am done.  I am so used to using
>classes now though that this is a 60 second thing.
>
>On the other hand, if this really is so generic that I use it all the time,
>I use a naming convention such that as a combo or list class loads it looks
>at it's name and hooks in the calls to that class to do the special
>processing for it.  Then you are right back to drag and drop convenience.
>I
>do this for the record selector combos at the top of my forms.  They use a
>naming convention and my combo class just "knows" that this is a record
>selector and when an item is selected in that combo the combo class finds
>the record selected and causes the form to display it.
>
>John W. Colby
>www.ColbyConsulting.com
>
>-----Original Message-----
>From: accessd-bounces at databaseadvisors.com
>[mailto:accessd-bounces at databaseadvisors.com]On Behalf Of Jürgen Welz
>Sent: Sunday, March 07, 2004 1:09 AM
>To: accessd at databaseadvisors.com
>Subject: RE: [AccessD] Your favorite control behavior
>
>
>That is almost exactly the way my Notinlist procedure is coded.  I also add
>two parameters, one for the target table to which the record will be added
>and one for a user name for the type of data to be added.  I guess the only
>difference is that I don't open a separate data entry form.  I just set a
>single record recordset for the existing form to the record that is added
>and it displays the new data in the appropriate field or fields.
>
>For things like date fields or lookups, I create them once on a template
>form and then copy from there to the form on which I need it displayed.
>Although you can use WithEvents and hook up controls, I haven't found a way
>to do this with the Notinlist parameters.  I have found that just about
>every event that I may want to use WithEvents for, I can instead create a
>public function procedure for.  For a control that displays a date for
>which
>I want a calendar to pop on double click and to change backcolor when it
>gets focus and revert to a non-focus backcolor when focus is lost, or
>respond to mouse move events, I can call the public procedure, usually
>passing in screen.activecontrol by using the function name rather than
>[eventprocedure] in the property sheet.  When I copy and paste a date
>control from my template form into a new target form, it is completely
>hooked up to all standard events.  Retrieving the form container name only
>requires the code to check the parent property of the active control.  For
>example, if you open the event property sheet for a conventional textbox,
>in
>the On Got Focus entry in the property you could enter:
>
>=OnFocus([Screen].[Activecontrol])
>
>and in the On Lost Focus entyr you could enter:
>
>=OffFocus([Screen].[Activecontrol])
>
>Then in a public module:
>
>Public Function OnFocus(ctl As Control)
>     ctl.BackColor = vbWhite 'or some standard constant
>End Function
>Public Function OffFocus(ctl As Control)
>     ctl.BackColor = -2147483633 'or some constant that can be set
>End Function
>
>You can check for control type being a combo and call .DropDown in the
>OnFocus or write a separate OnFocusCombo procedure.  The whole point is
>that
>the event procedures are hooked up  when you paste a copy of the control as
>the event properties are copied with the control.
>
>Another nice means to hookup events automatically is to create a control
>combination, or even a single control, encapsulated on a sub form all by
>itself.  The control comes with its own class module in the code behind the
>subform.  I have found this a great way to hookup something like a callback
>based list of municipalities with a not in list that can be made aware of
>the need to requery the data array when there is an addition or change to a
>municipality record.  No need to create a new copy of the control on
>multiple forms, just drag the subform container on and you get format and
>events all done.
>
>Ciao
>Jürgen Welz
>Edmonton, Alberta
>jwelz at hotmail.com
>
>
>
>
>
> >From: "Arthur Fuller" <artful at rogers.com>
> >
> >I have a function called aaNotInList() which takes the same parms as the
> >NotInList function and adds two new ones -- the name of the form to open
> >when adding an item, and the "human" name of said entity, the latter
> >just to pretty up the messagebox that comes up. The functon asks if you
> >want to add a new "XXX" (4th parm) and if so opens the specified form,
> >which uses the typical code to hide itself on OK and close itself on
> >Cancel. Then the function does the usual "add to list and accept the
> >value" and closes the form. It works great but I still have to type in
> >that line of code every time I need one. Not that one line of code is a
> >major hassle, I guess, but can you think of a class-based way to do
> >this? It might be more fun to do it that way.
> >
> >Arthur

_________________________________________________________________
MSN Premium includes powerful parental controls and get 2 months FREE*
http://join.msn.com/?pgmarket=en-ca&page=byoa/prem&xAPID=1994&DI=1034&SU=htt
p://hotmail.com/enca&HL=Market_MSNIS_Taglines

--
_______________________________________________
AccessD mailing list
AccessD at databaseadvisors.com
http://databaseadvisors.com/mailman/listinfo/accessd
Website: http://www.databaseadvisors.com






More information about the AccessD mailing list