I got stuck in a very annoying matter.
I need to open a form within a class module, passing the class itself to the form so that the form can use all of the class properties and methods.
I am talking about a form, NOT ABOUT A USERFORM. (The problem would not exist in this second case).
The form must be both popup and modal.
So let's suppose this code in the calling-class method that opens the form:
sub OpenFormMethodOfTheCallingClass
set MyForm = new [Form_FormToBeOpened]
with MyForm
set .MyFatherClass = Me
.SetFocus ' ... this opens the form
MsgBox "Ok, user has closed the form ..."
end with
end sub
This way, the code flow DOESN'T "STOP" INSIDE THE FORM.
I mean that the message "Ok, user has closed the form ..." appears immediately, "in front" of the opened form.
And then, obviously, the method ends and the form (again, obviously) disappears, as it's an instance of the closing method.
In design view, both Popup and Modal form are set to TRUE.
Setting the two properties in the calling procedure this way:
with MyForm
.Modal = True
.PopUp = True
(...)
... doesn't help at all, as:
- MODAL doesn't affect the code flow behavior
- POPUP can't be set (!): it returns a run-time error.
The only way I've found to achieve my goal is opening this way:
DoCmd.OpenForm "FormToBeOpened", WindowMode:=acDialog
This way, the code flow "stucks" into the form, and only when user closes the form itself the flow returns to the calling procedure, and its following instruction.
But the problem is that I can't pass the calling class to the form.
OK, someone could object that: as my form is MODAL, no multiple contemporaneous instances of the form can be opened by the user, and therefore I could pass any property of the calling class to the form in some other ways ("bridge-public-variables", or a JSON in OpenArgs ...). But it's ... really horrible.
I fear, don't know why, this is is a very stupid question, with a simple answer. :)
Let's see.
Thks,
FL
That's by design. Access runs a single thread, so dialog means dialog.
You can pass static values with OpenArgs to the dialog form, but you can also let this - when opened - pull data and properties from the calling form.
That code doesn't have to be ugly.
It may be that WinForms of .Net and Visual Studio will better fit your needs.
Create form class Form_Popup with .Modal and .Popup = True.
In Form_Popup's module
Add property variable, propFils_Class of type Fils_Class (or Variant, if not allowed)
Add Public Sub Let Fils_Class (inputFils_Class as Variant) and Public Sub Get Fils_Class (inputFils_Class as Variant) procedures to set and retrieve the propFils_Class
I'm assuming you need the input variables to be variants, but you may be able to pass them as Fils_Class type, not sure.
In the code requiring Form_Popup:
Dim frm as Form, varFils_Class as Fils_Class
'<set up varFils_Class here>
Set frm = New Form_Popup
'or Docmd.OpenForm "Popup" hidden etc., then you need to directly reference the form, e.g. Set frm = Forms("Popup")
frm.Fils_Class = varFils_Class
frm.Visible = True
Do While frm.Visible
Sleep 1
DoEvents
'<at some point actions on Form_Popup set .Visible to False>
Loop
varFilsClass = frm.FilsClass
'<do other actions with frm as needed>
set frm = Nothing
Related
I am trying to figure out how to make a Macro work in Access but have never used it before. The program is telling me there is a type mismatch. I cannot figure out what is wrong with the way it is written, but there is certainly an issue because it does not do what I wish. What I am trying to do is make a field visible when a checkbox is checked and invisible when it is not.
My Macro page looks like this:
If [Forms]![Form name]![Checkbox]=True Then
Set Property
Control Name: Control
Property: Visible
Value:True
Place this code in the VBA editor (in "your form name" code):
Private Sub Checkbox1_Click()
If Me.Checkbox1 = True Then
Me.Control1.Visible = True
Else
Me.Control1.Visible = False
End If
End Sub
Remember to change "Checkbox1" and "Control1" to the appropriate controls names.
I have a form with a subform (Datasheet view form). When i click a row in subform, i want pass that row value to text box in main form . In subform even wrote this
Private Sub Form_Click()
MsgBox (Noloan)
End Sub
But i don't know how to pass that subform form_click no_loan to mainform.textbox. Thanks for your help.
Additional data:In my db , i have a table which consist field No,NoLoan,Name. NoLoan Field value as i wanna clicked .From that table i create a subform/datasheet view ,subform name is T_Loan1. Then I create Main Form, name is FindLoan2. In that main/parent form i create text box, called Text7, and put T_Loan1 in subform object at footer.
I put this
=[Forms]![FindLoan2]![subformTLOAN].[Form]![Noloan]
in my Text7 Control and It's work.
Thank's for all attention.
Goto to the subform and click on the field which has the row value
Select Field property - click on events tab --> On Click --> Code Builder
Put below code in the Click event where Form_frmMain is your form name and Me.ID is the field.
Private Sub ID_Click()
Forms!FindLoan2.Text7 = Me.ID
End Sub
The best way is to write code that ignores the forms!names. If you copy the form, or change the sub form, or even drop the sub form into a different form, then all your code breaks.
To reference the textbox in the parent form from code, use:
me.Parent!Text7 = me!id
I am not sure which version of MS Access you are using, but it is also possible to use Tempvars to store values for use elsewhere if you have a complicated application which makes referencing another form/field/control difficult.
To create:
Tempvars.Add "TempVarName", TempvarValue
To use:
Tempvars!TempVarName
To remove:
Tempvars.Remove "TempVarName
I try to limit my use of them, as it becomes hard to manage. I am always careful about when I set the values and I ensure that they are removed after I am finished with them to avoid confusion or issues with values persisting when they shouldn't.
I am trying to display an error form, populated with text from a custom type object, as a MS-Access version of the fantastic answer on this Excel question.
The problem I run into is that I want to wait for a user response/confirmation on this error form, so it must be (as far as I am aware) a modal form and therefore I cannot just open the form and immediately populate it.
I have tried to find a way of doing in Access what was done in Excel; load the form, populate the form then display the form, but this doesn't seem possible since Access' event order is Open->Load->...
I have also tried looking for a way to open as a normal form, populate and then 'modalise' the form but could not find a way to do this.
Does anyone know of a way to achieve this function? Or is there an alternative to modal forms to pause execution awaiting user input?
A modal form is VERY different from a dialog form.
Modal forms do NOT cause the calling code to halt, but a dialog form does.
(do not confuse the two types of forms).
To “get back” a user response from a dialog form, simply set the form visible = false in place of a close form command. This will KICK the dialog form out of dialog mode, and your calling code now continues and the calling code is “free” to examine any values the user typed in or say choose from combo boxes, or check boxes, or whatever.
So your code block will look like this:
Private Sub Command0_Click()
Dim f As String
Dim strT As String
f = "formB"
DoCmd.OpenForm f, , , , , acDialog
If CurrentProject.AllForms(f).IsLoaded Then
' grab any values entered by user, or whatever buttons hit
strT = Forms(f).Text1
' etc. etc. etc. - grab values from that form
' don't forget to close the form
DoCmd.Close acForm, f
Else
' user canceled the form
' code goes here for user hitting your cancel button or "x"
End If
End Sub
And in your dialog form, the “ok” button, or “close” button simply goes:
Me.visible = False
If the user hits your cancel button, that code would be:
Docmd.Close acForm
So if the user hits “cancel” or even the “X” in the upper right corner, you consider and assume the user “bailed out”. When they do this, the form will be closed.
So the code after the dialog part simply checks if the form is STILL open (because your “ok” button does a visible = false).
And since the form is STILL open, then you are free to grab the values of ANY control – say user text typed into a text box, values from a combo box, check box, or whatever.
When user is done the calling code is free to examine or grab any value(s) from that form.
Edit - 2nd solution to allow "setting" of values.
This code will work:
Private Sub Command0_Click()
Dim f As String
Dim strT As String
f = "formB"
DoCmd.OpenForm f
Forms(f).Text1 = "Hello" ' set values on form
' now WAIT for user
Do While CurrentProject.AllForms(f).IsLoaded
If Forms(f).ok = True Then Exit Do
DoEvents
Loop
If CurrentProject.AllForms(f).IsLoaded Then
If Forms(f).ok = True Then
MsgBox "value return = " & Forms(f).Text1
Else
MsgBox "user cancel"
End If
DoCmd.Close acForm, f
Else
' cancel code goes here
MsgBox "user cancel"
End If
End Sub
The code for the OK button on the form B is now:
Me.Visible = False
Me.ok = True
And you need a public var "ok" in form B.
eg this:
Option Compare Database
Option Explicit
Public ok As Boolean
So the cancel button in form B can simply close the form. (you can close the form - but don't set ok = True)
So I have a form (frmBookingForm) in Access, and a listbox (lstMyBookings) that displays the results of a query.
Below this, I have a button (cmdDeleteBooking) which runs a delete query using the lstMyBookings selection as input. The button then runs a macro that firstly checks whether a record in the listbox is selected, and if one is, runs the delete query and requeries the data, so the deleted record is no longer shown in the listbox. If not, an error message is displayed.
However, if I then click the button again, it again runs the delete query, even though there is apparently nothing selected in the list box.
Essentially, how can I 'clear' the listbox selection?
I'd prefer a solution that can be done in a macro format, as I have little to no understanding of VBA. However, if providing a VBA solution, I'd greatly appreciate a short explanation of it.
Thanks :)
Looks like this website has a nice little function to do it. Essentially, you need to test if it's a multiselect, and then do one of two things. I suppose if you know ahead of time that it is/isn't a multiselect, you wouldn't even need the "if" statement:
If List0.MultiSelect = 0 Then
List0 = Null
Else
For Each varItem In List0.ItemsSelected
List0.Selected(varItem) = False
Next
End If
If the control's MultiSelect property is set to None, this code just sets List0 to Null. If the control's MultiSelect property is set to anything else, the code loops through all items that are currently selected, and sets the Selected property of that item to False. My example assumes your control is called List0.
EDIT
To use this code, use an event instead of a macro. Here's how you do this:
Right click on the button, select properties
In the Property Sheet window, click on the "Event" tab
Click inside of the "On Click" blank area, and click the dropdown arrow, then select "[Event Procedure]"
Click the ellipsis ("...") to go into the code editor.
In the code editor, your should already have your event for the button (let's assume the button is called Command1:
Private Sub Command1_Click()
End Sub
Add your code in between (assuming the listbox is called List0):
Private Sub Command1_Click()
If List0.MultiSelect = 0 Then
List0 = Null
Else
For Each varItem In List0.ItemsSelected
List0.Selected(varItem) = False
Next
End If
End Sub
My DB is split into Front and Back. I have three tables that I am working with in this problem; tblMain, tblDetail, tblNote. I know that the number of records is relatively small but I am designing this for long term use. I have a bound form (frmMain) for tblMain that has a subform (subDetail) for tblDetail. SubDetail has a subform (subNote) for tblNote. When I click a button on the main form, frmMain, the subDetail form becomes visible and allows me to add a new record. I copied the button and the VBA to subDetail so I could do the same thing for adding a record to subNote if needed. However, after the record is created, the subNote form disappears and focus is returned to subDetail. If I move to a new record then back, the subNote form becomes visible and shows an empty record except for the PK. I've checked all the properties of both subDetail and subNote. They are the exact same except for the OnCurrent event for subDetail. I have the following for the subDetail OnCurrent Event.
'Hide subform if no records
Private Sub Form_Current()
Me!ctrlmlsID.SetFocus
With Me!subNote.Form
.Visible = (.RecordsetClone.RecordCount > 0)
End With
End Sub
This hides or displays the subform, subNote, depending on if there is any records or not. Any help in figuring out this behavior would be appreciated.
Here is the code for adding a new record to subNote upon button click.
If Me.Dirty Then Me.Dirty = False
Dim AddTransID As String
AddTransID = Me!ctrlID.Value
Me!subNote.Visible = True
Me!subNote.SetFocus
DoCmd.GoToRecord , , acNewRec
Me!subNote.Form!ctrlID = AddTransID
Me!subNote.Form!ctrlType.SetFocus
I've used breakpoints and the adding record works just fine. It's just the subform going invisible again and the focus being changed back to the parent that is the issue because it won't allow those notes to be added.
I get the impression you are fighting Access here.
You normally do not need a button to create a new record using a properly bound subform with AllowAdditions = True. That will happen automatically.
The problem you are running into may stem from the fact that the new records don't really exist yet until saved (as you observe there is no PK value). So the logic to hide subforms isn't going to work. If you insist on staying with this approach you might try
.Visible = (.RecordsetClone.RecordCount > 0 or .NewRecord)
But I think your life will be easier if you remove the buttons and code you have mentioned and let Access do what it is good at doing. Make sure your subform data binding properties are set right.