I have a ListBox in access 2013 , I need to pass values from (form1) to (form2) after double click on Lisbox in (form1). I have already try this way:
The below code when (form2) is activated , it worked normally but if forms
property popup = true
It not working , values cannot read in (form2) .
Private Sub Form_Activate()
If CurrentProject.AllForms("SearchFrm").IsLoaded = True Then
BBAIDHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(0)
PrNumberHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(1)
SupplierHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(2)
OrderDateHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(3)
TransactionTypeHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(4)
TotalValueHidenTxt.Value = Forms![SearchFrm]![SearchList].Column(5)
End If
End Sub
note : i'm new in access database developing
A dialog Popup form stops all code on the calling form until the 2nd form opened is closed.
Pass the value(s) in an Openargs property to the Popup.
You can use TempVars or Pubic Variable defined in module to store the value and later access them in other form.
Best option is to use OpenArgs option as already mentioned by Minty.
Form1
Private Sub listBox_DblClick(Cancel As Integer)
Dim lstStr As String
lstStr = Me.listBox.Column(1)
DoCmd.OpenForm "SearchFrm", acNormal, , , , acDialog, lstStr
End Sub
Form2
Private Sub Form_Load()
If Not IsNull(Me.OpenArgs) Then
MsgBox Me.OpenArgs
End If
End Sub
Related
I have a subform with a button that opens another form.
On the secondary form, the user can select an address.
The selected address should be applied to the calling form.
I pass the window handle when opening the child form.
But when it tries to find the calling form in the Forms collection, it isn't there.
I suspect that is because the calling form is actually a subform.
I don't know where to go from here.
Calling the form, passing the windows handle
OpenCCCustAddr [CustFID], "CCInt", Me.hWnd
In the Form Close event, I try to set the address values on the calling form,
but GetFormByHWND returns null.
Set frm = GetFormByHWND(Me!txtCallingHWND)
// Me!txtCallingHWND here is populated and looks reasonable
frm!BillStreet = strAddr // This blows up since frm is null
frm!HolderZipCode = strZip
frm!AddressUpdated = -1
Set frm = Nothing
Public Function GetFormByHWND(lngHWND As Long) As Form
Dim frm As Form
Dim nm As String
Select Case lngHWND
Case 0
Case Else
For Each frm In Forms
nm = frm.NAME // the name of the parent form shows, but not my calling subform
If frm.hWnd = lngHWND Then
Set GetFormByHWND = frm
Exit For
End If
Next
End Select
End Function
For Each and For I=0 to Count-1 both give the same results. The form just isn't in Forms. It's possible that it is because it is a subform.
I tried searching the subforms, but this blows up when I check ctl.hWnd with "Object doesn't support this property"
Public Function GetFormByHWND(lngHWND As Long) As Form
Dim frm As Form
Dim ctl As Access.Control
Dim nm As String
Select Case lngHWND
Case 0
Case Else
For Each frm In Forms
nm = frm.NAME
If frm.hWnd = lngHWND Then
Set GetFormByHWND = frm
Exit For
End If
Next
Rem If we didn't find the form, check for a subform
If GetFormByHWND Is Nothing Then
For Each frm In Forms
nm = frm.NAME
For Each ctl In frm.Controls
If ctl.Properties("ControlType") = acSubform Then
nm = ctl.NAME
If ctl.hWnd = lngHWND Then // Error: "Object doesn't support this property"
Set GetFormByHWND = ctl
Exit For
End If
End If
Next
Next
End If
End Select
End Function
As #June7 pointed out, my mistake was assuming that the control was the form. Instead is has a form.
So the proper solution is
Rem If we didn't find the form, check for a subform
If GetFormByHWND Is Nothing Then
For Each frm In Forms
For Each ctl In frm.Controls
If ctl.Properties("ControlType") = acSubform Then
If ctl.Form.hWnd = lngHWND Then // note the change here
Set GetFormByHWND = ctl.Form
Exit For
End If
End If
Next
Next
End If
First, it not at all clear why all that code and hwn stuff is required?
We assume that you have a form.
On that form, you have a button, and it launches the 2nd form.
so, in first form, we have this:
' write data to table before launching form
If Me.Dirty = True Then Me.Dirty = False
DoCmd.OpenForm "formB"
Ok, now in formB on-load event, we have this:
Option Compare Database
Option Explicit
Dim frmPrevious As Form
Dim frmPreviousSub As Form
Private Sub Form_Load()
Set frmPrevious = Screen.ActiveForm
Set frmPreviousSub = frmPrevious.MySubFormControl.Form
' do whatever
End Sub
So now we have both a reference to the previous form, and also the sub form.
Say the user selects some address and hits the ok button.
The code then does this:
frmPreviousSub!AddressID = me!ID ' get/set the PK address ID
docmd.Close acForm, me.name
So no need for all that world poverty, grabbing and looping hwnd or any such hand stands.
Just a few nice clean lines of code.
Now, I DO HAVE a recursive loop that will return the form handle ALWAYS as a object reference, and you thus don't even have to hard code the form(s) name.
So, say that main form had 2 sub forms, and on those to sub forms, you have
A Company address, and a ship to address. So, you want to launch form B from EITHER of these two sub forms, and when you select a address, you return that value, and thus two or even potential 3 sub forms could in fact call this way call pop up address selector form.
The way you do this is similar to the above code, but we do NOT need to hard-code the sub form.
The code will now look like this:
Private Sub Form_Load()
Dim f As Form
Set f = Screen.ActiveForm ' pick this up RIGHT away -
' previous active form only valid
' in open/load event
' we have the previous active form, get the sub form.
Set frmPrevous = GetSubForm(f)
End Sub
Note that the sub form can be 3 or even 5 levels deep. This routine is "recursive". It grabs the previous form, then checks if a sub form has focus. If the sub form has focus, then it gets that control, and if that control is a sub form, then it just keeps on going until such time we drill down this rabbit hole and NO MORE drilling down can occur.
This routine should be placed outside of the form and placed in your standard "global" module of routines.
Public Function GetSubForm(f As Form) As Form
Static fs As Form
If f.ActiveControl.Controltype = acSubform Then
GetSubForm f.ActiveControl.Form
Else
Set fs = f
End If
Set GetSubForm = fs
End Function
So note how if it find that a sub form has the focus? Well then it just calls itself again with that form and keeps on drilling down. As a result, it don't matter if the form is 1 or 5 levels deep. The resulting "frmPrevous" will be a valid reference to that sub form, and thus after you select or do something in the supposed popup form? You can set the value of some PK or whatever and then close the form.
There is no hwnd, very clean code, and the recursion trick means that even for nested sub forms more then one deep, your frmPrevious is in fact a reference to the form that launch the form we pop up for the user to select whatever.
If you don't have a common Address ID column? Then our popup form should ASSUME that you always have a public variable defined in the calling form.
Say ReturnAddressID as long
Make sure you dim the value as public, say like this:
Public ReturnAddressID as long
So, now in our popup form, we can do this:
frmPrevious.ReturnAddressID = me!PD
frmPrevous.MyUpdate
(we assume that all forms that call the popup also have a public function names MyUpdate.
Thus, now we have a generalized approach, and 2 or 10 different address forms, even as sub forms can now call the one address picker. As long as any of those forms adopts that public ReturnAddressID and a public function MyUpdate, then we can pass back the values, and MyUpdate will shove/take/set the ReturnAddressID into whatever column and value you use for the Address ID in that sub form.
And of course if there are no sub forms, the routine will just return the top most form that called the pop up form.
There is a sub, it creates a CourtForm userform and then takes a data from it. The problem appears when said form is closed prematurely, by pressing "X" window button and I get a runtime error somewhere later. For reference, this is what I'm talking about:
In my code I tried to make a check to exit sub:
Private Sub test()
'Create an exemplar of a form
Dim CourtForm As New FormSelectCourt
CourtForm.Show
'The form is terminated at this point
'Checking if the form is terminated. The check always fails. Form exists but without any data.
If CourtForm Is Nothing Then
Exit Sub
End If
'This code executes when the form proceeds as usual, recieves
'.CourtName and .CourtType variable data and then .hide itself.
CourtName = CourtForm.CourtName
CourtType = CourtForm.CourtType
Unload CourtForm
'Rest of the code, with the form closed a runtime error occurs here
End Sub
Apparently the exemplar of the form exists, but without any data. Here's a screenshot of the watch:
How do I make a proper check for the form if it's closed prematurely?
Add the following code to your userform
Private m_Cancelled As Boolean
' Returns the cancelled value to the calling procedure
Public Property Get Cancelled() As Boolean
Cancelled = m_Cancelled
End Property
Private Sub UserForm_QueryClose(Cancel As Integer _
, CloseMode As Integer)
' Prevent the form being unloaded
If CloseMode = vbFormControlMenu Then Cancel = True
' Hide the Userform and set cancelled to true
Hide
m_Cancelled = True
End Sub
Code taken from here. I would really recommend to have a read there as you will find a pretty good basic explanation how to use a userform.
One of the possible solutions is to pass a dictionary to the user form, and store all entered data into it. Here is the example:
User form module code:
' Add reference to Microsoft Scripting Runtime
' Assumed the userform with 2 listbox and button
Option Explicit
Public data As New Dictionary
Private Sub UserForm_Initialize()
Me.ListBox1.List = Array("item1", "item2", "item3")
Me.ListBox2.List = Array("item1", "item2", "item3")
End Sub
Private Sub CommandButton1_Click()
data("quit") = False
data("courtName") = Me.ListBox1.Value
data("courtType") = Me.ListBox2.Value
Unload Me
End Sub
Standard module code:
Option Explicit
Sub test()
Dim data As New Dictionary
data("quit") = True
Load UserForm1
Set UserForm1.data = data
UserForm1.Show
If data("quit") Then
MsgBox "Ввод данных отменен пользователем"
Exit Sub
End If
MsgBox data("courtName")
MsgBox data("courtType")
End Sub
Note the user form in that case can be closed (i. e. unloaded) right after all data is filled in and action button is clicked by user.
Another way is to check if the user form actually loaded:
Sub test()
UserForm1.Show
If Not isUserFormLoaded("UserForm1") Then
MsgBox "Ввод данных отменен пользователем"
Exit Sub
End If
End Sub
Function isUserFormLoaded(userFormName As String) As Boolean
Dim uf As Object
For Each uf In UserForms
If LCase(uf.Name) = LCase(userFormName) Then
isUserFormLoaded = True
Exit Function
End If
Next
End Function
I have a Parent Form with a Sub Form and I want the user to be able to select a record from the sub form, then click a button on the Parent Form, which will launch a "new" form that has full demo's pertaining to the selected record from the sub form.
How would I do this in Access 2013?
You can pass the ID as a parameter when opening the "new" form.
On your button's Click event:
Private Sub Command0_Click()
'Get the ID
Dim id_ As Long
id_ = Me.SubformName.Form!ID
'Open the new form and pass the ID to the .OpenArgs
DoCmd.OpenForm "FormName", acNormal, , , acFormPropertySettings, acWindowNormal, id_
End Sub
On the Form's Load event, check the .OpenArgs and filter the form (or whatever else you need to do) to the supplied ID.
Private Sub Form_Load()
With Me
If Not IsNull(.OpenArgs) Then
.Filter = "[ID]=" & .OpenArgs
.FilterOn = True
.Caption = "ID: " & .OpenArgs
End If
End With
End Sub
I have created a VBA UserForm which is essentially a glorified input box
Just like an input box can be employed like this
Dim returnVal As String
returnVal = InputBox("Write some string")
I would like my userform to run like this
Dim returnVal As customClass
Set returnVal = MyUserForm([some arguments])
ie. the MyUserForm() code passes some arguments to the userform, and when the userform is closed, it gets some arguments back (in the form of a custom class rather than a plain string)
What's the best way of structuring my userform to allow this functionality?
Currently, I'm just declaring some variables and the custom class publicly. I'm catching command button clicks and Query_close() events to hide the form, then I read the outputVal and close the form completely. I don't like this because I'd like my form to be totally self contained, and I think the capturing of events is messy.
In simplified code (read/return a string):
Function myUf(inVal As String) As String
Dim frm As New frmTest
frm.inputval = inVal
frm.Init 'sets caption. We cannot rely on userform initialize as this runs before inputval is set
'We could pass a variable here to save writing to the public variable
frm.Show
myUf = frm.outputVal
Set frm = Nothing
End Function
And in my Userform called frmTest with a textbox called tb1
Public inputval As String
Public outputVal As String
Public Sub Init()
Me.Caption = inputval 'setting caption, but could pass this anywhere
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode <> 1 Then Cancel = 1
outputVal = tb1 'reading value from textbox, but could return anything here
Me.Hide
End Sub
You need to find a way to initiate the UserForm from a ClassObject. Then, you can use a simple factory pattern to create the UserForm exactly the way you want.
In general, I have copied a bit of the code of Mat's Mug somewhere in StackOverflow and I wrote an article about the User Forms. If you take a look here (http://www.vitoshacademy.com/vba-the-perfect-userform-in-vba/) you will find a way to initialize the form with Public Sub ShowMainForm() It's possible to add a parameter to the ShowMainForm, then pass it to the initializer of the class.
In general, take the code from the article, make sure it works, and change the ShowMainForm initializer to the following:
Public Sub ShowMainForm(strText As String, strText2 As String)
If (objPresenter Is Nothing) Then
Set objPresenter = New clsSummaryPresenter
End If
objPresenter.Show
Call objPresenter.ChangeLabelAndCaption(strText, strText2)
End Sub
Then, if you call like this in the immediate window:
call ShowMainForm("Just","testing")
You will get this:
Which is quite what you need. :)
The basic idea is:
Create a Function in witch you combine your arguments to a string like:
strOpenArg = "param1:=value1;param2:=value2;"
than open the form with the OpenArgs
DoCmd.OpenForm "UserForm", acNormal, , , , acDialog, strOpenArgs
get your value and close the Form
Value= Form_UserForm.Value
DoCmd.Close acForm, "UserForm", acSaveNo
in the UserForm set Form_open. Here you can get your parameters.you can devide this by string splitting.
Set also an OK Button, where you make the form just invisible and set the return value
Private Sub Form_Open(Cancel As Integer)
Dim strParameter as String
strParameter = Me.OpenArgs 'Here are your parmeters
End Sub
Private Sub ok_Click()
m_Value = "Your ReturnValue"
Me.Visible = False
End Sub
Private m_Value As String
Public Property Get Value() As String
Value = m_msgBoxResult
End Property
There's no way to one-liner the code like you want to, unfortunately. If all your userform code is self-contained then the only way for it to pass values out is to change the values of public variables. Mat's Mug's answer here is the layout I usually use when trying to simulate functions like 'InputBox' but you still can't get it in one line without writing a separate function. Using userform properties allows you to contain more of your code within the form itself.
I want to populate a textbox on a form using VBA. I want it to first open the form, then go to a New record and then populate a textbox on that New record.
Private Sub btn_AddAccount()
DoCmd.OpenForm "tbl_MonitorAccounts", , , , acFormAdd, acDialog, NewData
DoCmd.GoToRecord , , acNewRec
Me.MonitorAccount = "FUNC00265"
End Sub
Please help me because the code above does not work unfortunately.
Edit: I think it has to do something with that the field is bound. Is it possible to populate bound records using VBA?
Changing acFormAdd to acFormEdit was the easy solution.
Private Sub btn_AddAccount()
DoCmd.OpenForm "tbl_MonitorAccounts", , , , acFormEdit, acDialog, NewData
DoCmd.GoToRecord , , acNewRec
Me.MonitorAccount = "FUNC00265"
End Sub
Yes, can populate bound control. I expect it doesn't work because the form opens in Dialog mode and this suspends code execution in the calling procedure which resumes when the Dialog form closes.
Have code behind Dialog form populate textbox if condition is met. The code opens form in Add mode so should not need more code to move to new record, should already be on new record row. Example:
Private Sub Form_Open(Cancel As Integer)
If Me.NewRecord Then
Me.MonitorAccount = "FUNC00265"
End If
End Sub
Or can pass value to the Dialog form with OpenArgs and do something depending on what is in OpenArgs. Ex: If Me.OpenArgs Like "Edit*" Then