Return Value from Form

  • Thread starter Thread starter Jonathan Wood
  • Start date Start date
J

Jonathan Wood

I need to return a value from a form displayed modally.

Many years ago, if I used VB classic, I could create a public method that
took care of any arguments, displayed the form modally, and then returned
appropriate return values. Something like this:

Public Function GetValue(Args As Integer
m_Args = Args
m_Result = DefaultResult
Show vbModal
GetValue = m_Result
End Function

However, it appears Access VBA doesn't support this. For one thing, there's
no Show method (and so it certainly can't have a modal argument).

I like this approach because it provides a clean, easy interface for calling
code to deal with.

Has anyone found a clean way to do this using MS Access?

Cheers!

Jonathan
 
I need to return a value from a form displayed modally.

Many years ago, if I used VB classic, I could create a public method that
took care of any arguments, displayed the form modally, and then returned
appropriate return values. Something like this:

Public Function GetValue(Args As Integer
m_Args = Args
m_Result = DefaultResult
Show vbModal
GetValue = m_Result
End Function

However, it appears Access VBA doesn't support this. For one thing, there's
no Show method (and so it certainly can't have a modal argument).

I like this approach because it provides a clean, easy interface for calling
code to deal with.

Has anyone found a clean way to do this using MS Access?

One way is to open the form in Dialog mode; the calling code will stop until
the called form is either closed - OR made invisible. For example, you can put
a Close button on the form that doesn't actually close the form, just does

Me.Visible = False

You could then have code like

DoCmd.OpenForm "YourFormName", WindowMode:=acDialog
GetValue = Forms!YourFormname!Controlname
DoCmd.Close acForm, "YourFormName"
 
Thanks.

This is certainly not what I'm after since I'm trying to encapsulate the
functionality so the calling form doesn't need to deal with this.

Unless... Can I use this technique from a public method on the same form
that's being shown? And, if so, could I then return a form-level variable
value instead of the value of a control?

And while I'm here <g>, is there clear documentation on when I can use . and
when I have to use ! ? I always seems to get confused on this.

Cheers!

Jonathan
 
Jonapthan Wood said:
I need to return a value from a form displayed modally.

Many years ago, if I used VB classic, I could create a public method that
took care of any arguments, displayed the form modally, and then returned
appropriate return values. Something like this:

Public Function GetValue(Args As Integer
m_Args = Args
m_Result = DefaultResult
Show vbModal
GetValue = m_Result
End Function

However, it appears Access VBA doesn't support this. For one thing,
there's no Show method (and so it certainly can't have a modal argument).

No, but you can open the form as dialog, and "dialog" is set in your code,
not
in the forms property sheet. Keep in mind that modal forms and dialog forms
are
two different things and types of forms in access. (we have both). model
does
not cause code to wait, but dialog forms DOES halt the calling code.

So, lets say we need a form with a combo box, a check box..and some other
things
that we need returned BACK from that form.

Hence, the code looks as

' lets open a prompt form
strF = "frmGetComboName"
docmd.OpenForm strF,acNormal,,,,acDialog

' the above code opens our form "frmGetComboName", and the waits until the
user
enters some data, and then hits ok. The code behind the ok button in the
GetName form does NOT close the form, but does a

me.Visible = false

' at this point, either the user hit ok, or closed the form. If the form is
still open, then user did not cancel, and we assume he hit OK. Setting
visible = false is what kicks the form OUT OF dialog mode and calling code
now continues to run

if isloaded(strF) = true then
' code goes here to example values
strName = forms(strF)!ThenameField
strSex = forms(strF)!GenderField
' ok, got our data...lets close the form (don't forget this!!)
docmd.Close acForm,strF
else
' if the form is not open, then user hit the "x", or the cancel
' button on the frmGetComboName form. Note that the cancel button on
' this form simply does a docmd.close
msgbox "user canceled"
end if

You have to handle the cancel logic anyway (even in VB6 you did). So, the
above is really not any more code. The whole code snip thus looks like:

strF = "frmGetComboName"
docmd.OpenForm strF,acNormal,,,,acDialog
if isloaded(strF) = true then
' code goes here to grab values, or even
' variable values (members of the form)
strName = forms(strF)!ThenameField
strSex = forms(strF)!GenderField
someVar = forms(strF).m_publicVarValue
' ok, got our data...lets close the form (don't forget this!!)
docmd.Close acForm,strF
else
' if the form is not open, then user hit the "x", or the cancel
' button on the frmGetComboName form. Note that the cancel button on
' this form simply does a docmd.close. So, code goes here for cancel:
msgbox "user canceled"
end if

You also need the code for isloaded. It can be found in tons of examples,
and also in the northwind traders. It is reproduced below my sig
just in case you don't have it:

You can also thus wrap the whole acDialog form code in a function that
returns a value if you want. I do this for date calendar prompts, and
you thus get re-usable form that can be used anywhere by a simple function.

So, the ability in this case to return values is thus much like vb6.

The above code + example is here:

http://www.members.shaw.ca/AlbertKallal/Dialog/Index.html


--
Albert D. Kallal (Access MVP)
Edmonton, Alberta Canada
(e-mail address removed)


Function fIsLoaded(ByVal strFormName As String) As Integer
'Returns a 0 if form is not open or a -1 if Open
If SysCmd(acSysCmdGetObjectState, acForm, strFormName) <> 0 Then
If Forms(strFormName).CurrentView <> 0 Then
fIsLoaded = True
End If
End If
End Function

And, in access 2003 and later, you don't need the above function and can
use:

currentproject.AllForms("Name of form").IsLoaded
 
Jonathan Wood said:
Thanks.

This is certainly not what I'm after since I'm trying to encapsulate the
functionality so the calling form doesn't need to deal with this.

You can see my other example. You can write the code + call in a public
function if you wish.
Unless... Can I use this technique from a public method on the same form
that's being shown? And, if so, could I then return a form-level variable
value instead of the value of a control?

You can use + return a form level var. The issue is when + how + where
do you want the code to "wait"? You code snip assumes that the form
waits for user input, and the continues. You might want to expand on
where that code snip is actually running. I assumed the code example
was running outside of the form.

Perhaps I am missing a detail here. Are you planning on using multiple
instances of the SAME form open at the same time, or should just the one
instance of the form be ok here?

Any var declared as public in a form does automatic become a member of
that form (which is in fact a class object). You can thus examine and
use those values in code (even in/from other forms). So, you you are
free to look at, examine, or set those variables in that form's code module.
(and you can do so from other forms).
And while I'm here <g>, is there clear documentation on when I can use .
and when I have to use ! ? I always seems to get confused on this.

Yes, join the party! This is a source of issues.

I can give you a really long story, but I'll give you the short one.
There's some internal tricks that Access often does to enable both ! (bang)
and "." (dot) to work in instances when only one of them really is the
correct syntax.

Short version:

to examine values (controls) on a form use "." (dot)

So, me.ControlName (for code inside the form) or

form ref + .Controlname for code outside of the form

To examine fields from the underlying record set of the form, use !

The above means that if you actually delete a control on a form, or use a
illegal control, the
compiler will catch if you use "."

If you use bang, it will not matter if the control is actually placed on the
form or not. You can still use and examine the forms underlining record
field value. Your code will compile regardless if a control of the same name
is on the form or not.

The above is a short version, and is not 100% entirely true, but it's enough
to get you going fast.
 
You could just create a class with one property MyFormReturnValue. Start
your application from a Module Sub Main and make your class instance in the
module Public. You would be able to set the property and retrieve it from
anywhere in the application.
 
Albert said:
You can see my other example. You can write the code + call in a public
function if you wish.

Thanks for the very detailed replies. For me, the bottom line is that Access
VBA doesn't let me encapsulate functionality the way I can in VB classic and
other languages I use. At this point, I'm kind of leaning towards just
creating a global variable and have the form set that.
You can use + return a form level var. The issue is when + how + where
do you want the code to "wait"? You code snip assumes that the form
waits for user input, and the continues. You might want to expand on
where that code snip is actually running. I assumed the code example
was running outside of the form.

Yes, kind of like a dialog box getting user input. I was just looking to
better encapsulate whatever that form does, so the calling code didn't need
to delve into that. In classic VB, I could create a public method in the
form and have that method load the form. In Access, just calling the public
method loads the form that contains it.
Perhaps I am missing a detail here. Are you planning on using multiple
instances of the SAME form open at the same time, or should just the one
instance of the form be ok here?

One instance, although I was trying to come up with a slick approach that I
could use for different forms (at different times).
Any var declared as public in a form does automatic become a member of
that form (which is in fact a class object). You can thus examine and
use those values in code (even in/from other forms). So, you you are
free to look at, examine, or set those variables in that form's code
module.
(and you can do so from other forms).

But I want to be able to expose one so it can be read by code outside the
form.
Yes, join the party! This is a source of issues.

I can give you a really long story, but I'll give you the short one.
There's some internal tricks that Access often does to enable both !
(bang) and "." (dot) to work in instances when only one of them really is
the correct syntax.

Short version:

to examine values (controls) on a form use "." (dot)

So, me.ControlName (for code inside the form) or

form ref + .Controlname for code outside of the form

To examine fields from the underlying record set of the form, use !

The above means that if you actually delete a control on a form, or use a
illegal control, the
compiler will catch if you use "."

If you use bang, it will not matter if the control is actually placed on
the form or not. You can still use and examine the forms underlining
record field value. Your code will compile regardless if a control of the
same name is on the form or not.

The above is a short version, and is not 100% entirely true, but it's
enough to get you going fast.

Thanks. I think I can remember that. :-)

Jon
 
Jonathan Wood said:
Thanks for the very detailed replies. For me, the bottom line is that
Access VBA doesn't let me encapsulate functionality the way I can in VB
classic and other languages I use. At this point, I'm kind of leaning
towards just creating a global variable and have the form set that.

Darn, I missed this response..but, in case....

I don't see how access is different here.
But I want to be able to expose one so it can be read by code outside the
form.

Sure, nothing stopping from doing that. I stated "and you can do so from
other forms".

All vars and functions declared as public in the forms code becomes
properties and methods of that form.

I don't see this as being different in VB6 at all in regards to returning
values from that form. The ONLY issue you not clearing up here is WHEN do
you know that the user is done on that form, and the calling code is to
continue? You can simple adopt a standard that your close event calls a
public property in the calling form called

frmDoneLetsContinue

You don't need, nor should be resorting to global vars for this solution.
 
Back
Top