Trying again (MVP, please note): programmatically setting up event handlers

S

sjg1314

I have a small database, but it has 11 Forms and and even more subforms
and special purpose forms. I'm an expert programmer but an MS Access
2000 Visual Basic beginner. As I learn more about the language, I find
myself going back and making similar changes to many of the Forms.
Often I have to put little bits of code in multiple places--besides
being monotonous, the chances of slipping up somewhere is pretty high.

So I'd like to centralize code as much as possible so that there is one
place I can go to make changes to all Forms or all Forms of a certain
type. In order to use some of the techniques I know, I have to
programmatically set up event handlers.

For instance, to set a resize handler for all Forms, I could create a
subroutine that gets called whenever a Form is opened or loaded. This
method would set a Form's OnResize property to "=handleResize()".
Great!

Now I want to do the same for an error handler. The problem is that the
Error event has two parameters, DataErr and Response, and its not
useful without them. Is there any way to programmatically set up the
event handler to call something like "=handleError(DataErr, Response)".

Now, I know I can set up an OnError handler that then calls my
subroutine. This requires that I go into the Form, set the OnError
property to "[Event Procedure]" and then type some code that transfers
the work my special method. This is better than nothing, but not much
better, because I don't just want to do this for Forms, I want to set
up handlers for Controls in a Form.

For example, I may want a Focus handler for all text and combo box
fields in a form. With code, I can cycle through all the Controls in
the Form and set up the handlers (which actually works for Focus events
because they don't have any arguments). Without program automation, I
have to go to each control and set up the GotFocus and LostFocus
handlers for each of them. If I create a new text or combo box field, I
have to remember to set up the handlers.

I suspect that this is hole in VBA 2000 that I'll just have to live
with, but I'm hoping to get either an authoritative "can't be done" or
"here's how to do this" or even "here's an alternate way to solve the
problem".

Thanks!
 
A

Albert D.Kallal

In the case of passing those parameters, you have to enter the code, and
there is no way to pass the values that I know of.

You might be able to sink the events into a class object using the
"withevents", but, I don't think so...
(you might be able to sink the events..but you would have hard code the
forms declaration, and that gets you nothing
-- you do realize that each form is a class object, and that you can have
multiple instances of the SAME form open, but this info does not really help
you).

On the other hand, since a form only has the one error event, it is not a
lot of code to write anyway :)

For controls, often you need pass a bit of information anyway. For example,
MANY of my "not in list" events for a combo box need to add a new record to
the not in list event. To make the software more user friendly, you still in
MOST cases need to have some control, and SOME information that describes
the not in list event at hand.

So, my "general" catch all not in list code looks like

Private Sub cboArea_NotInList(NewData As String, Response As Integer)


Call comboAdd("not in the pub area list", "tblPubArea", "Area", NewData,
Response)


End Sub

Note how I had to pass the "newdata" + "response" to the routine. All combo
boxes have this, and as you mention, it would be NICE to be able to simply
put the above function right into the combo box handler. However, if you
look at the above, I also need to specify the table, (tblPbuArea), and also
the field name (Area), and MOST important is the custom text ("not in the
area list".).

Since I find that SOME level of customizing tends to occur for many of these
events, then building a nice routine, and manually entering the information
tends to give better results, and MORE flexibly since I can ENTER DIFFERENT
parameters for some of the values. Since you OFTEN have to enter DIFFERENT
parameters, then simply dropping down into the code editor makes a lot of
sense anyway. When the event has several parmatmers, you find that a "catch
all" routine is not very often needed anway.

Also, when you right click on a buttion, or other contorls, can choose build
event, you can ELIMONATE the prompt

Expression Builder
Macro Builder
Code Builder

The above prompt can be elimonated by going

tools->options->forms/reports tab

[x] - Always use Event procedures.

If you check the above box, then It saves you one click EVERY time..and you
are ALWAYS transported right to the code editor, and you do NOT get the
above 3 prompts.
....
I don't know if the above option is available in a2000, but it REALLY nice
feature (certainly available in a2003).....
 
S

sjg1314

Hi, Albert,

Thanks for your detailed reply. The bottom line sounds like
In the case of passing those parameters, you have to enter the code, and
there is no way to pass the values that I know of.

Who designs this stuff? I even tried using the variable arguments
interface and received no parameters. It looks like Microsoft calls an
event handler with arguments and a function without.

As far as coding, it isn't the number of mouse clicks I use that's the
problem. Let me give an example. I have a button that performs a given
function when clicked and which is enabled or disabled based on other
events. In order to add this button to a new form, I have to add bits
of code in several places. After the fifth or sixth form, I start
getting a confused about which forms I've altered and whether I copied
the right code into all the right places. I'd rather have one method I
could put into the OnOpen event, something like

addSomeCapability myButton, "custom text for button"...(and other
customization)

The idea is that this one subroutine would set up all the right event
handlers and all the right pieces of code.

It's even worse when I realize two days later that my button handling
code has a problem. I have to go back to all the little pieces of code
(event if each one is just one line) and make some changes. It's hard
to be sure that I caught all the changes.

Anyway, it sounds like that's just the way it is. If anyone agrees or
disagrees, I'd still be happy to hear it.

By the way, MS Access 2000 does have the "Always use event handlers"
option. Thanks for pointing it out.
 
G

Guest

I'm relatively dumb when it comes to programming--just a warning...

Why can't you just create a module, write a SUBroutine and then call it for
each form. That way, you only need to add the subname once to whatever form
or button you are using. Then you can just alter the called subroutine code
itself, which would subsequently affect how all the forms handle the button.

Or am I completely missing what you are asking?
 
A

Albert D.Kallal

Who designs this stuff?

What environment have you used that allows runtime resolution of your
function names? I just curious as to what you used that allows your code to
resolve a name at runtime?
addSomeCapability myButton, "custom text for button"...(and other
customization)

The idea is that this one subroutine would set up all the right event
handlers and all the right pieces of code.

Well, you can certainly write some code to open the form in design mode, and
make the changes. However, we are now talking about code that modifies other
code.

To define, and have your code change/modify at runtime is rather
daunting...do you think?

As I mentioned, exactly what developer background do you come from where
this is common practices? Perhaps some scripting environment that is
evaluated at runtime, and not compile time?
It's even worse when I realize two days later that my button handling
code has a problem. I have to go back to all the little pieces of code
(event if each one is just one line) and make some changes. It's hard
to be sure that I caught all the changes.

I note sure why the one line of code that CALLS YOUR "general" error routine
would need to be modified? (or your general contorl code?).

Why would the number of parameters change there?
This makes no sense at all. If those controls call your "general" code, it
is VERY unlikely that the calling code will need to be changed, or modified.
At the very most, we would be talking about a VERY small instance when this
happens. Having to modify the main code module that those controls calls
certainly makes sense, and you will often have to modify that code. But,
modify the calling code of one line? Hum, not a problem here.

You can download a free copy of mz-tools, and when in ANY routine, it will
pop up a list of CALLING routines. So, you could just open up your error
routine in the standard module, and a list of forms code that calls the code
would be available. However, this begs the question....are you really
saying that you have to change the parameters of those controls that calls
error code? I am hard pressed to ever much having to remember to do this,
and even more hard pressed to this ever being a developer problem.
..
Perhaps you are not explain something fully here?

Anyway, the free mztools is a great vba add-in, and you can find it here:

http://www.mztools.com/
 
S

sjg1314

I have a button to which I want to add some common functionality. I
want it to create a new record on the OnClick event. I want it to be
disabled on the OnCurrent event if the record is a NewRecord;
otherwise, it should be enabled. I want it to be enabled once the
OnDirty event occurs. I picked this example sort of at random and I'm
assuming at least one of these event handlers passes in a parameter we
need. If not, you'll need a different example.

Now try to write a single subroutine which accomplishes all this. If I
could set the event handlers programmatically and include the
arguments, then yes, I'm all set. If none of the events I was
interested in had parameters, then I'm also all set. Finally, if
someone had a way of accessing those parameters when the event handler
is set using "=functionName()", then I would have a complete solution.

Which is why I asked the question. A lot of the interesting events have
a Cancel or Response argument which is difficult to do without.
 
S

sjg1314

Albert said:
What environment have you used that allows runtime resolution of your
function names? I just curious as to what you used that allows your code to
resolve a name at runtime?

Hi, Albert! Let's see...how about PHP? :)

I've worked for many years with the Java event handling mechanism,
which allows you to programmatically add as many event handlers as you
want for any event. You don't add a function, you add an object, but it
works out to the same thing--when the event occurs, some custom code
gets executed.

In any case, I wasn't asking for runtime resolution of function names,
I was asking for the ability to set up event handlers programmatically,
which is what most other languages allow (since they usually don't come
with a built-in IDE, they have to allow it).
Well, you can certainly write some code to open the form in design mode, and
make the changes. However, we are now talking about code that modifies other
code.

To define, and have your code change/modify at runtime is rather
daunting...do you think?

If that is what I wanted to do, then perhaps it would be..or maybe it
wouldn't. I'm happy to leave this to the philosophers. I just want to
be able to programmatically set up any and all event handlers.
As I mentioned, exactly what developer background do you come from where
this is common practices? Perhaps some scripting environment that is
evaluated at runtime, and not compile time?

Every language I know (other than VB for Access) that supports event
handlers, supports programmatically setting the event handlers. I'm
sure if Access didn't have a built-in IDE, it would, too. This has
nothing to do with scripting environments. I could event create a
system for doing this in VBA (after all, event handling is not usually
a language construct--it's part of the programming framework), but it
wouldn't help me out unless I could modify the base Form class to use
my event handler system.
I note sure why the one line of code that CALLS YOUR "general" error routine
would need to be modified? (or your general contorl code?).

In my case, the button handling code involves two event handlers on the
Form and one on the button.
Why would the number of parameters change there?

Since this is all theoretical examples (based on real problems I've run
into), let's assume I figure out a way to improve the usability of the
button, but it obsoletes a parameters I was passing it and requires a
different value. And perhaps the change even requires adding some code
to yet another event handler.
This makes no sense at all. If those controls call your "general" code, it
is VERY unlikely that the calling code will need to be changed, or modified.
At the very most, we would be talking about a VERY small instance when this
happens. Having to modify the main code module that those controls calls
certainly makes sense, and you will often have to modify that code. But,
modify the calling code of one line? Hum, not a problem here.

Let's agree to disagree.
You can download a free copy of mz-tools, and when in ANY routine, it will
pop up a list of CALLING routines. So, you could just open up your error
routine in the standard module, and a list of forms code that calls the code
would be available. However, this begs the question....are you really
saying that you have to change the parameters of those controls that calls
error code? I am hard pressed to ever much having to remember to do this,
and even more hard pressed to this ever being a developer problem.
.
Perhaps you are not explain something fully here?

I am, as always, thinking of much broader examples. Forget the error
handler--that's just an example of an event handler that's useless
without the parameters. I've been putting in some code that requires
multiple event handlers to function properly. So for each Form, I have
to go in and add multiple pieces of code in various places. Then if I
come up with a better idea, I may have to remove, revise and/or add to
all these little pieces of code.

In Java, not only would it be easy to centralize all this, but I could
even have the controls that are associated with this functionality
appear automatically!

VB for MS Access is the first language with event handling that I've
run into that requires the use of the IDE in order to get fully working
event handlers. Who designs this stuff? :)
Anyway, the free mztools is a great vba add-in, and you can find it here:

http://www.mztools.com/

Thanks for the tip!
 
A

Albert D.Kallal

(since they usually don't come
with a built-in IDE, they have to allow it).

Ah, but they don't have a built in forms object either...do they?

The problem here is not the IDE, but the fact that you have a forms object
that is already made for you, and is not
a "generated" piece of code...

If you plan to build and write your own forms object from scratch, then this
is not a problem.....

Further, as mentioned, it is not much work to put that ONE line of code in
the event of your choice anyway. (so, it not a big problem). In fact, you
could certainly add a list of PUBLIC functions to a form. Remember, ANY
function defined as public becomes a method of that form. You still have to
put in the calling code (stub) for each control, but as I said before, this
is generally not a problem.

I do think that the events of a forms object should be able to be sunk into
a class object module. In fact, in some cases, you can do this, but as I
mentioned, you wind up hard coding the forms object anyway. The use of
withevents is explained here:

http://www.databaseadvisors.com/newsletters/newsletter052002/0205CombiningRaiseEvents .htm

but it
wouldn't help me out unless I could modify the base Form class to use
my event handler system.

Well, VB6, and ms-access allow the use of class objects, but they are not a
OO language. You simply have to put in code stubs. I suppose you could write
code to generate those stubs for you.....
 
S

sjg1314

Albert said:
with a built-in IDE, they have to allow it).

Ah, but they don't have a built in forms object either...do they?

Actually, they do...

For instance, in Java, the equivalent of a form is a "Frame".
The problem here is not the IDE, but the fact that you have a forms object
that is already made for you, and is not
a "generated" piece of code...

I agree.
If you plan to build and write your own forms object from scratch, then this
is not a problem.....

I thought about it :) Actually, controls have events as well, so I'd
have to rewrite them too.
Further, as mentioned, it is not much work to put that ONE line of code in
the event of your choice anyway. (so, it not a big problem).

As I said, it may be one line of code in multiple event handlers. And
if the functionality involves, say, all text controls, then not only is
there a lot of typing but you have to remember to add some code with
each text control you add later.

For instance, let's say I want to do something each time a control gets
focus and loses focus. That's two lines per control times the number of
controls in a Form equals a lot of lines.
I do think that the events of a forms object should be able to be sunk into
a class object module. In fact, in some cases, you can do this, but as I
mentioned, you wind up hard coding the forms object anyway. The use of
withevents is explained here:

http://www.databaseadvisors.com/newsletters/newsletter052002/0205CombiningRaiseEvents .htm

Thanks for the pointer!
Well, VB6, and ms-access allow the use of class objects, but they are not a
OO language. You simply have to put in code stubs. I suppose you could write
code to generate those stubs for you.....

Could you? Hmmm... you mean create a separate program that would go
through all the controls in use and produce the right stubs for the
form and all the controls? Sounds like a possibility--not perfect, but
perhaps the only way to get this going.

With an alternate event system, you could also add support for multiple
handlers for one event (another goal of mine). For example, if I set up
a got/lost focus handler for all controls to do one thing, I might
occassionally want to do something else with focus events. With the
right event system, you could completely encapsulate the two functions
so they would neither know nor care about each other.

Thanks for the lively discussion and tips, Albert!
 
A

Albert D.Kallal

Well, VB6, and ms-access allow the use of class objects, but they are not
Could you? Hmmm... you mean create a separate program that would go
through all the controls in use and produce the right stubs for the
form and all the controls?

Yes. Furhter, in place of code, you could also use macros, and that would be
easier. (the fomrs boject model, and including mehtoeds to edit, and
add/delete code are exposed).

However, you could even export the meta information of a form. Try the
follwing from the debug window

saveastext acForm,"name of form","c:\myform.txt"

And, the reverse of the above is
saveastext

I would actually use macros in this case, since they would be less complex
to change via code, and would NOT re-set the compile bit/flags as compared
to actually modifying code....

Now that I think about this, you can't programalliy put in the function name
into the control (with the parameters as you ask) without self modify the
souce code --- but you sure the heck can do this with macros + vba code.....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top