'Push' property to form opened in Dialog mode?

  • Thread starter Thread starter Tom
  • Start date Start date
T

Tom

Is it possible to set any properties on a form that is
opened with vba in dialog mode?

For instance, I would like to control whether a command
button on the form being opened is Visible based on
conditions in the calling code. However, when the form is
opened in dialog mode the code following a DoCmd.OpenForm
method wont take affect until after the form has closed.

The best approach I know is to set these properties in the
Load event of the form based on parameters passed to it by
the calling code, but the form in question is used in
several different contexts and I would rather not risk
breaking it if there is a way to sneak in properties when
opening it in dialog mode.


Any help appreciated!, and thanks in advance,

Tom
 
Probably many ways to do this, but here's a quick and dirty for you.

Create a global boolean variable in one of your standard modules (create one
if you have none). Give it a name, something like gblnSetFormProperties
(call it whatever you like, as long as it relates to the task you are using
it for).

Before you open the form in dialog mode from somewhere in your app, set
gblnSetFormProperties to True:

e.g.

gblnSetFormProperties = True
DoCmd.OpenForm "frmYourForm", acNormal, , , acFormEdit, acDialog

In the forms Load event, use an If...Then statement to check if
gblnSetFormProperties = True. If it is, set the form properties you want
and then set gblnSetFormProperties back to False:

e.g.

Private Sub Form_Load()
If gblnSetFormProperties = True Then
'Have some code here to do your bidding
gblnSetFormProperties = False
End If
End Sub

Hope this helps.

Jamie
 
Use the OpenArgs argument of the OpenForm method to pass a string to the
dialog form. The dialog form can read that string and do what you want with
its contents.
 
Is it possible to set any properties on a form that is
opened with vba in dialog mode?

Here is two good solutions:

#1, pass the parameters (you already hinted at this idea)

So, you just pass a bunch of primers via open args:

dim strFormParms as string

strFormParms = "Parm1,Parm2,Parm3,ParmFour,Parmfive"

docmd.OpenForm "myCoolDialogForm",,,,,acDialog,strFormParms


in the forms on load, you simply setup your parms to some module variables
for the form:


m_Parm1 = split(me.OpenArgs,",")(0)
m_Parm2 = split(me.OpenArgs,",")(1)

etc. etc. etc.

Idea#2:
Simply ASSUME that all calling forms will setup the parmaters BEFORE you
call. You then in the on-load go:

set frmCalling = screen.ActiveForm

Note that frmCalling is again defined at the forms MODULE level..so all code
anywhere in this acDialog form can use the "previous" form

As mentioned, in the calling form, we assumed all parmaters would be setup

m_Parm1 = "one"
m_Parm2 = "two"

docmd.OpenForm "MyDialogForm",,,,,acDialog

Now, in the on open event, we go:

set frmCalling = screen.ActiveForm
m_Parm1 = frmCalling.m_Parm1
m_Parm2 = frmCalling.m_Parm2
etc. etc. etc.

Note that the vars in the called form do need to be declared as public, but
can remain in the forms module.

Any good developer will tell you to AVOID using global vars to solve these
kinds of problems....

Note that you can also now use any feature of the previous form, for
example:

frmCalling.Requery
 
Ouch! Well, I never claimed to be good. Albert, could you help me out by
elaborating on why it is not a good idea to use global variables for this
sort of thing?

TIA

Jamie
 
Hi Albert,

Whilst I think it would've been nicer of you to confine your critique solely
to the answer I offered (as opposed to the "any good developer" crack), I
liked your solution and have learned something new, thanks. I would just
like to check something. Given that Tom uses the form in various situations,
wouldn't it be possible that there are no OpenArgs passed? In that case is
it necessary to test if OpenArgs exist before assigning the values, or does
the code you posted handle this some other way?

If Not (Me.OpenArgs & "") = "" Then
m_Parm1 = Split(Me.OpenArgs, ",")(0)
m_Parm2 = Split(Me.OpenArgs, ",")(1)
End If

Or some similar method?

Jamie
 
Ouch! Well, I never claimed to be good. Albert, could you help me out by
elaborating on why it is not a good idea to use global variables for this
sort of thing?

My global comments were not actaully direclted to you! It is common
to see solutiosn that use glaobls.

However, let me elinoate on globals:

In fact, if you can avoid global for passing values, you always
should.

First, if you use global vars, then you got some variables and defines that
are "out there" some where. In other words, we got two forms, and some code.
Now, we got also to look, worry about, and have some *knowledge* of some
other variables that we are using, and they are not part of our current
code solution. Think of your self as a developer going into the project
without prior knowledge as to how things work. When you got global vars all
over the place, it makes it VERY HARD to understand the code. So, instead
of two forms and some code, we added in a 3rd code module with some global
variable defs.

Global vars means your code is not modular. You spend some of your precious
time making two nice forms work together. A few months later, you go..hey, I
need those two forms to do the same thing in another project. You import the
two forms...and they don't work, because now you have to also go and hunt
down some global vars. It is question of ease of maintainability of your
application
that globals effect. The reverse is also true. You decide to import some
forms into your application. You as a habit may use the "same" global vars
to
pass values between forms. Now, you got more then one set of forms that use
those same global vars...and you don't know this...a real nice way to
introduce bugs...

Further, we all know that forms allow multiple instances. You might have a
design where you are looking at a customer, and the phone rings. Your users
can minimize the current customer form, and then bring up another customer
(ms-access allows multiple copies of the SAME form to be loaded at the same
time). So, now, if your design decides that you can have two copies, or
more of the same form opened at the same time, then once again globals will
not work..will they? Which set of forms opened do the globals vars apply to?
So, in a windows type environment, we allow multiple instances, and again
globals will kill any design that allows multiple instances of the same
window.

Even worse, we all OFTEN make a copy of the forms to do something similar in
the application. Another part of the application may be VERY similar to the
current part we are working on, and thus we copy the forms, and start
working away. The problem is now, we got this global dependency to worry
about in the code, and again if the other forms get used, then we got a
problem with the *same* global vars being used. So, globals are not a very
modular approach to coding. I mean, for example we can go:


globalParm1 = "Albert Kallal"

Call MyCoolSub


Public Sub MyCoolSub

msgbox "name passed = " & globalParm1

It is MUCH better to go:

Call MyCoolSub("Albert Kallal")

Public Sub MyCoolSub(strName as string)

msgbox "name passed = " & strName


I mean, ask your self why do we not normally use globals in the above
example? (we, CAN use globals...but we DO NOT!). As a rule, one
likely avoids using globals as above since the code is
INDEPENDENT of everything else. We can copy that code, we can modify that
code
without fear that we "forgot" or left out some global var. We also don't
have to
worry that if we copy, or modify the code, then we are breaking something
else.
The whole reason why parameters are an advantage between subs and functions
is
that we thus don't have to define global vars to pass information.

If you got code that uses globals all over the place, then it becomes VERY
hard to change ONE thing without effecting a zillion other things. Hum, I
am about to change one variable, is there 200 other subs and forms that
use the variables? Will changing the value effect every single sub, (or in
our
case form) in the whole application? Can I use it...can i change it?

The key to maintainable code and applications is to reduce the dependences
and the
zillion number of places to look for, and the zillion number of places that
can cause your code to break. You change a value of a global var that
something else is using, then you got a big problem.

So, simply passing values between two subroutines, or passing
values between two forms, the exact same philosophy, and good concepts of
development apply.

Now, without question, globals should, and can be used for things are
global. Things like user name, logon information etc. These things are
needed
by the whole application, and thus make sense to be globals.

However, to pass a simple value between two subs, or between two forms,
globals simply introduces dependencies and increases the difficulty at
which you can re-use code, and maintain the project.
 
If Not (Me.OpenArgs & "") = "" Then
m_Parm1 = Split(Me.OpenArgs, ",")(0)
m_Parm2 = Split(Me.OpenArgs, ",")(1)
End If
You can go:

If isnull(me.OpenArgs) = false then
.....
 
Hi Albert,

Thanks for your detailed explanation. I feel a little better now. I have
no formal training and was thinking that I have been doing things wrong for
a couple of years (one of the pitfalls of learning as you go I guess -
picking up bad habits).

I have used OpenArgs frequently, but not when I needed something complex to
happen on the form called. The use of Split is fantastic and something I
will adopt. As for the use of globals, I take your point about modular
design, and as a rule I only use application wide variables in globals and I
do not re-use one variable for more than one task (again, as a rule). I
have a module called basGlobals in which to store things like user info,
global recordsets (where I need to persist data after closing a form) and so
on. I group and comment all variables in this module. So to some extent I
am already doing what you advised. However I will change my practice of
using globals to perform the things we have discussed.

Your advice is greatly apreciated. Thank you.

Jamie
 
Thanks everyone for the very helpful responses!

I guesss I will have to work on the code in the form that
I am opening to get the desired effect... I am already
using a single OpenArg when the form is opened, but I will
definitely try out the split() approach to combine
multiple parameters.

Thanks again for the help.

Tom
 
Albert D. Kallal said:
Global vars means your code is not modular.

Another common term that is relevant here is "object-oriented".

I agree with everythig you said and it is all very useful and relevant. Most
of it also applies to the object-oriented philosophy and it would be useful
to also describe what you say in that context too. The term "modular" is
relevant to structured-programming philosophy, which is also very useful and
does not get as much credit as it deserves.

However you certainly did say the most important points.
 
Albert D. Kallal said:
Here is two good solutions:

#1, pass the parameters (you already hinted at this idea)

So, you just pass a bunch of primers via open args:

dim strFormParms as string

strFormParms = "Parm1,Parm2,Parm3,ParmFour,Parmfive"

docmd.OpenForm "myCoolDialogForm",,,,,acDialog,strFormParms


in the forms on load, you simply setup your parms to some module variables
for the form:


m_Parm1 = split(me.OpenArgs,",")(0)
m_Parm2 = split(me.OpenArgs,",")(1)

etc. etc. etc.

Idea#2:
Simply ASSUME that all calling forms will setup the parmaters BEFORE
you call. You then in the on-load go:

set frmCalling = screen.ActiveForm

Note that frmCalling is again defined at the forms MODULE level..so all
code anywhere in this acDialog form can use the "previous" form

As mentioned, in the calling form, we assumed all parmaters would be setup

m_Parm1 = "one"
m_Parm2 = "two"

docmd.OpenForm "MyDialogForm",,,,,acDialog

Now, in the on open event, we go:

set frmCalling = screen.ActiveForm
m_Parm1 = frmCalling.m_Parm1
m_Parm2 = frmCalling.m_Parm2
etc. etc. etc.

Note that the vars in the called form do need to be declared as public,
but can remain in the forms module.

Any good developer will tell you to AVOID using global vars to solve these
kinds of problems....

Note that you can also now use any feature of the previous form, for
example:

frmCalling.Requery

If I were using C++ and MFC, I would do something such as:

COpenDialog OpenDialog;
OpenDialog.m_IPAddress = SocketAddress;
OpenDialog.m_Port = Port;
OpenDialog.DoModal()

Where:
· COpenDialog is a class for a dialog
· OpenDialog is an instance of the dialog
· m_IPAddress and m_Port are member variables of the COpenDialog class
· DoModal() is a member function (method) that shows the form

In other words, I would create a class for the dialog that has relevant
member variables, then create an instance of the class, then set the member
variables to the values to be used by the dialog class, then show the
dialog. In the COpenDialog class, I would use the m_IPAddress and m_Port
member variables to initialize the dialog.

In reply to me in another thread, you said that "a form is a class object".
So can a form be used in the manner described above? If not, then I assume
that a class can be created for a form in a manner that is the VBA
equivalent of the C++ and MFC code above.

In another reply to another thread ("Information about class modules ?") you
referenced:

http://www.attcanada.net/~kallal.msn/Articles/WhyClass.html
http://www.microsoft.com/OfficeDev/Articles/classmod.htm
http://www.microsoft.com/AccessDev/Articles/GetzCh3.HTM

I assume those are relevant here.
 
Back
Top