This code is just meant to figure out a total and then a percentage of that total, and then display the percentage amount in a textbox. This code runs when a button on a form is clicked, but it uses data based in a subform on that form, and the textbox that it should display to is on the form. Both the form and the subform are invoked in the class list, so it confuses me as to why it comes up with an "Object Required" error.
Private Sub cmdTest_Click()
'Initialisation
Dim TotalAmount As Integer
Dim GiftAid As Integer
'Processing
If AllForms!frmGiftAid!subfrmqryGiftAid!PaymentIncrement Is Not Null Then
If AllForms!frmGiftAid!subfrmqryGiftAid!PaymentIncrement = "Monthly" Then
TotalAmount = _
(AllForms!frmGiftAid!subfrmqryGiftAid!PaymentAmountPerIncrement * 12)
Else
TotalAmount = _
AllForms!frmGiftAid!subfrmqryGiftAid!PaymentAmountPerIncrement
End If
End If
'Termination
GiftAid = (TotalAmount * 0.25)
AllForms!frmGiftAid!subfrmqryGiftAid!subfrmqryGiftAidtxtGiftAid = GiftAid
End Sub
The line that the error occurs on is the first one that references the subform, so it's:
If AllForms!frmGiftAid!subfrmqryGiftAid!PaymentIncrement Is Not Null Then
I've tried using different variations of the code to reference the subform (just referencing the subform, using "Forms" instead of "AllForms") as well as trying it in the subform itself rather than the form and doing so on different events, such as On_Current() or On_Load(), but nothing has worked for me so far.
Any help that you could offer me would be greatly appreciated.
Reference the subform starting either with Me from the code module of the form, or Form, followed by the name of the form. You then have the name of the subform control, Form, to refer to the object contained, and finally and property of the contained form.
Forms!frmGiftAid!subfrmqryGiftAid.Form!PaymentIncrement
Or
Me.subfrmqryGiftAid.Form.PaymentIncrement
Note that it is important to use the name of the subform control, not the name of the form contained.
This code would run on the parent form and a record would need to be selected on the subform.
If Not IsNull(Me.subfrmqryGiftAid.Form.PaymentIncrement) Then
If Me.subfrmqryGiftAid.Form.PaymentIncrement = "Monthly" Then
TotalAmount = _
Me.subfrmqryGiftAid.Form.PaymentAmountPerIncrement * 12)
Else
TotalAmount = _
Me.subfrmqryGiftAid.Form.PaymentAmountPerIncrement
End If
End If
Related
I have a command button on a form which opens a separate form to only a new record that matches the Contact ID of the current form. This second form exists so I can establish a relationship between my contact and a new group, which is a one-to-many relationship as each contact can be in more than one groups, but some contacts aren't in any group.
Some users will be assigning existing contacts to a new group, and some users will be adding new contacts to an existing group, so I want the form establishing relationships between contacts and groups to exist independently from either the contacts form or the groups form. This is why I didn't simply create a subform on the contacts form. I don't know which direction my users will be coming from when editing relationships, and ideally I'd like to set up a system where the form the user is coming from will create a new record with one of the two fields (contact and group) auto-populated depending on the "parent" form. That is, if my user is accessing the relationships form from a contact form, I will see a new record with the ContactID filled in and I can select a group. Similarly, if a user is accessing the relationships form from a group form, that group will be filled in and the user will select a contact.
I have the following subroutine On Click of my command button on the contacts form:
Private Sub CmdAssignContactGroup_Click()
DoCmd.OpenForm "frmContacts_Groups", , , , acFormPropertySettings
[Forms]![frmContacts_Groups]![ContactID] = [Forms]![frmContacts]![ContactID]
End Sub
This works for any one contact, but when I move to a different contact without closing the contact form, the filter criteria remain the same and the command button brings me to the record in the contacts/groups form attached to the previous contact.
How can I tell the command button to reset after I change records within the contact form?
This answer uses the DefaultValue and the Locked property of a Control to pin the ContactID (if form is opened by frmContacts) or the GroupID (if form is opened by frmGroups) to the opening form values.
I assume two ComboBoxes in frmContacts_Groups that are bound to their IDs, but display the names of Client/Group, named cboContactID and cboGroupID.
Code in frmContacts_Groups:
Private Sub Form_Load()
Dim OpeningID As Long
Select Case Me.Openargs
Case "frmContacts"
OpeningID = Nz(Forms!frmContacts!ContactID,0) ' Nz to prevent errors on empty opening form
Me.Filter = "ContactID = " & OpeningID
Me.cboContactID.DefaultValue = OpeningID
Me.cboContactID.Locked = True
Me.cboGroupID.DefaultValue = vbNullString
Me.cboGroupID.Locked = False
Case "frmGroups"
OpeningID = Nz(Forms!frmGroups!GroupID,0)
Me.Filter = "GroupID = " & OpeningID
Me.cboContactID.DefaultValue = vbNullString
Me.cboContactID.Locked = False
Me.cboGroupID.DefaultValue = OpeningID
Me.cboGroupID.Locked =True
Case Else
Me.cboContactID.DefaultValue = vbNullString
Me.cboContactID.Locked = False
Me.cboGroupID.DefaultValue = vbNullString
Me.cboGroupID.Locked =False
Me.Filter = vbNullString
End Select
Me.FilterOn = Len(Me.Filter) > 0
End Sub
Code for opening in frmContacts:
Private Sub CmdAssignContactGroup_Click()
If Not CurrentProject.AllForms("frmContacts_Groups").IsLoaded then
DoCmd.OpenForm FormName:="frmContacts_Groups", OpenArgs:="frmContacts"
Else
Msgbox "frmContacts_Groups is allready opened! What should we do?"
End If
End Sub
Your where-condition does not relate to the form to be opened but to the currently open form, as you reference ContactID with [Forms]![frmContacts_Groups]![ContactID]. I.e. you pass the result of the comparison of the currently open forms (True or False) instead of passing a condition that will be evaluated by the opening form.
You must pass it a condition as text like "ContactID = 10".
Dim condition As String
condition = "ContactID = " & Me!ContactID
DoCmd.OpenForm "frmContacts_Groups", WhereCondition:=condition
Since ContactID is on the same Form, you can access it with Me!ContactID. It also looks like you are erroneously passing the condition as the WindowMode parameter.
Also make sure the properties of the frmContacts_Groups Form are
AllowEdits = Yes
AllowDeletions = No
AllowAdditions = No
and most important!
DataEntry = No
If DataEntry is Yes, then the form will jump to the new record!
Before opening the form, you could also call
DoCmd.Close acForm, "frmContacts_Groups"
to make sure the previous edits of a possibly still open form do not interfere with the new edits.
I am trying to create a function that will allow me to use various command buttons without having to recreate the code every time.
To do this I have to pass the form name through a function
Function:
public Function NewRecord(controlForm, focusForm)
focusForm.SetFocus
DoCmd.GoToRecord , , acNewRecord
controlForm.SetFocus
controlForm - This is the main form akin to the Me function
focusForm - This is for not only the main form but when I create subforms I have to have the focus on the subform to have the command work.
To call the function I did the following:
public sub Command19_Click()
Dim controlForm
Dim focusForm
Set controlForm = Forms![frm_Sales_CustomerProfile]
Set focusForm = Forms![frm_Sales_CustomerProfile]
Call NewRecord(controlForm, focusForm)
End Sub
I get this error that States: Compile Error: Invalid Use Of Property.
You got trapped using an already in this context (the form) used identifier and not using a strong name (NameOfLibrary.NameOfFunction).NewRecordis a forms property, soInvalid Use Of Propertymakes sense. If you useMyModulName.NewRecord(frm1,frm2)everything is fine. If you useNewRecordin Module òr Class it works too as there is no property with same name (I assume;-)).
To be honest, I don't use strong names either (except on database or recordset objects, as I got trapped there too, assuming DAO, using ADODB), but the Pros suggest that and now we know why!
Your function should have just one argument as it is sufficent to pass only the subforms reference if you need that form NewRecord(frm as Access.Form) (note the strong name!). You can easy refer to the mainform with Set mfrm = frm.Parent
Your code;
Public Function FrmNewRecord(frm As Access.Form)
frm.Recordset.AddNew
End Function
Public Sub Command19_Click()
FrmNewRecord(Forms![frm_Sales_CustomerProfile]) ' mainform
FrmNewRecord(Forms![frm_Sales_CustomerProfile]!sfrmControl.Form) ' subform
End Sub
You are passing the same form two times in your code, any reason? If Forms[frm_Sales_CustomerProfile] contains Command19 use Me.
I dropped the .SetFocuspart as not necessary or any reason to for setting focus? Why is NewRecord a function? Doesn't return anything.
btw: I am working on aSubForms(frm)function , that returns a collection of all subforms.
Code:
'SubForms(frm As Access.Form) returns a collection of all subform references in frm
Public Function SubForms(frm As Access.Form) As VBA.Collection
Dim ctr As Access.Control
Dim sfrm As Access.Form
Dim col As New VBA.Collection
For Each ctr In frm.Controls
If ctr.ControlType = acSubform Then
On Error Resume Next
Set sfrm = ctr.Form
If Err.Number = 0 Then
col.Add sfrm, sfrm.Name
End If
On Error GoTo 0
End If
Next ctr
Set SubForms = col
End Function
As a general rule to build say custom menu bars, or ribbons, you can write code that is “form” neutral like this:
Public Function MyDelete(strPrompt As String, strTable As String)
Dim strSql As String
Dim f As Form
Set f = Screen.ActiveForm
If MsgBox("Delete this " & strPrompt & " record?", _
vbQuestion + vbYesNoCancel, "Delete?") = vbYes Then
So note how we don’t need to pass the form name at all – the above code simply picks up the active screen as variable “f”.
At that point you can do anything as if the code was inside the form.
So
Me.Refresh (code inside the form)
Becomes
f.Refresh
So the key concept here is that you don’t need to pass the current active form since screenActive form will enable you to get the current form object anyway.
However, for sub forms and “common” type of code the above falls apart because screen.ActiveForm will return the main form, and not the sub form instance.
So as a second recommended approach, simply always pass the current context form object “me” like this:
Call MySub(me)
And you define your sub like:
Sub MySub(f as form)
Now in this code we can reference "anything" by using "f" in place of "me"
f.Refresh
So just pass “me” if you ever use sub forms. Given the above information, then your code becomes:
public sub Command19_Click()
Call NewRecord(me)
End Sub
And NewReocrd becomes:
Sub NewRecord(f as form)
Now in your newreocrd code, you can use “anything” form the object such as:
f.Name ' get name of the form.
or
City = f.City ' get value of city control
So pass the “whole” form context.
And you could say make a routine to display the City value for any form like:
Call ShowCity(me, "City")
And then
Sub ShowCity(f as form, strControlToShow as string)
Msgbox "City value = " & f(strControlToShow)
So OFTEN one will write code that works for any form by simply picking up the current active form as:
Dim f As Form
Set f = Screen.ActiveForm
And note how the above code picks up right away the active form – this is a good idea since then if focus changes, the “f” reference will remain intact for the code that follows in that “general” routine that is called + used from many forms.
However due to the sub form issue, then often it simply better to always pass the “whole” forms instance/object with:
Call MyNewRecord(me)
And then define the sub as:
Sub MyNewReocord(f as form)
DoCmd.GoToRecord acDataForm, f.Name, acNewRec
End Sub
And you could optional add “focus” to above with
f.SetFocus
So for a lot of menu or ribbon code, you don't pass the form object, but simply use screen.ActiveForm, and you can also use Screen.ActiveControl (again great for menu bar or ribbon code to grab what control has focus). However due to sub form limitations, then often passing "me" to the routine will achieve similar results if not better in some cases.
I'm a newcomer to Access trying to cobble things together from helpful information I've found here.
I have a form that needs to populate the fields based on a combo box selection in the form header. The form is based on an underlying query with the following criteria for field "StudID" [Forms]![frmStudConsentUpdate]![cmbStud] where cmbStud is my combo box. The combo box pulls in StudID, StudFN, StudLN with StudID as the bound columnn. The after update event requeries the form (Me.Requery). This works beautifully, but only if I first open the form in design view, open the Record Source, and save it. I don't make any changes at all, but once I've done this the form works. Otherwise, nothing happens when I select a student in the combo box. Any thoughts on what I need to do to make this work without having to re-save the underlying query?
This is old bug in MS Access, I have no idea why they still didn't fix it:
If underlying form's query has in criteria form's control and the form was filtered once (at start or manually/using VBA), it doesn't accept new values from form's control and uses old value.
Workaround: create public function, which returns control's value and use it in criteria instead of [Forms]![frmStudConsentUpdate]![cmbStud]. You will need to create function for each control or use this function:
Public Function GetControlValue(strFormName As String, strControlName As String, Optional strSubFormControlName As Variant, Optional varDefault As Variant) As Variant
' Returns : Variant, value of control in form/subform
' Comments:
' Params :
' strFormName
' strControlName
' strSubFormControlName
' varDefault - value returned if control is not accessible
'----------------------------------------------------------------------------
On Error GoTo ErrorHandler
If IsMissing(strSubFormControlName) Or Nz(strSubFormControlName, "") = "" Then
GetControlValue = Forms(strFormName).Controls(strControlName).Value
Else
GetControlValue = Forms(strFormName).Controls(strSubFormControlName).Form.Controls(strControlName).Value
End If
ExitHere:
On Error Resume Next
Exit Function
ErrorHandler:
If Not IsMissing(varDefault) Then
GetControlValue = varDefault
End If
Resume ExitHere
End Function
In criteria use function call GetControlValue("frmStudConsentUpdate","cmbStud") instead of [Forms]![frmStudConsentUpdate]![cmbStud]
In your afterupdate for your cmbStud combobox, create code that refreshes the recordsource to
me.recordsource = "SELECT * FROM {yourQueryName} WHERE StudID = '" & me!cmbStud & "'"
i have my regular form with a continous form attached to it. Everything works fine untill the subform has no data.
Here is the subform with data
image1
IF there are no data in the subform, the form becomes like this.
image 2
I am using the following code in my on current event on my main form:
Function RefreshCOunt()
If Me.frmVerifyEquipmentSub.Form.Recordset.RecordCount = 0 Then
Me.frmVerifyEquipmentSub.Visible = False
Me.txtTotal = 0
Me.Refresh
Else
Me.frmVerifyEquipmentSub.Visible = True
Me.frmVerifyEquipmentSub.Form.Requery
Forms![test3].txtTotal = Me.frmVerifyEquipmentSub.Form.txtSum
Me.Refresh
Forms![test3].Refresh
End If
End Function
Private Sub Form_Current()
Call RefreshCOunt
End Sub
Private Sub Form_GotFocus()
Call RefreshCOunt
End Sub
Here is the code on my subform, THis function is run when my user clicks the save button.
Function RefreshCOunt()
If Me.txtCount = 0 Then
Forms![test3].SetFocus
Else
Me.Requery
Forms![test3].txtTotal = Me.txtSum
Me.Refresh
Forms![test3].Refresh
End If
End Function
I have a text behind the subform which says "NO Available Data to be shown"
2 problems in this situation are:
Empty form view as shown on image 2 (resolved as i had linked the record source of the main form to the table also used in subform)
Hide the subform once the user has verified all the equipment.
-currently my code only works the first time the form is loaded.
-the subform does not hide once the user has verifed all the equipment
I know how to do this in report with the HAsData function but i am not sure how i can do so in Forms.
It sounds like your query for the main form has an inner join to the table (or a query with this table) for the subform.
Remove this join or change it to an outer join.
I have a form MyForm1 with a module having the method.
Public Sub CreateSQL(ProductID as variant)
Me.Recordsource = " SELECT * FROM ProductOrders " _
" WHERE ProductID = " & Nz(ProductID ,0)
Me.Requery
End Sub
I use this as a subform to a form named MyMainForm.
When I change the value of a control on MyMainForm it successfully executes the following line:
Me.Subform1.Form.CreateSQL ProductID:=Me.cboProductID
My Questions:
Why are the members not listed on the intellisense list that appears after I type Me.Subform1.Form.?
Is there a way of getting them to be listed?
Is there a property that will let me access the "Form_MyForm1" class of the form referenced in the subform control "Source object property" (ie the Me.Subform1.form ) ?
It's like I need to be able to write:
Me.Subform1.Form_MyForm1.CreateSQL ProductID:=Me.cboProductID
Does such a property already exist? If so how do I access it? Is it in the properties collection?
PS: If you need more information please see the same questions posted in a long Stack overflow question here
Harvey
Don't know.
Not that I know of.
Make the subfunction Public.
But it looks like you could save yourself a lot of trouble by using the Master/Child link option of a form and its subform control.
Instead to the mainform calling the method Me.Subform1.Form.CreateSQL
You should create an object variable in the subform that points to the main form and responds to events eg:
Dim WithEvents cvMyParentForm As Form
Property Set MyParentForm(MyParentForm As Form)
Set cvMyParentForm = MyParentForm
End Property
Property Get MyParentForm() As Form
Set MyParentForm = cvMyParentForm
End Property
When the main form opens use the Form_Open event to "initialise" the subforms
Private Sub Form_Open(Cancel As Integer)
If Me.Subform1.Form.MyParentForm Is Nothing Then
Set Me.Subform1.Form.MyParentForm = Me
End If
End Sub
then you can get the subform to respond to the FORM events that are raised by the mainform.
If you need to have the subform respond to any events that you declare in the main form you will need to chnaeg the above code to use the Form_MyMainFormname type
Dim WithEvents cvMyParentForm As Form_MyMainFormName
Property Set MyParentForm(MyParentForm As Form_MyMainFormName)
Set cvMyParentForm = MyParentForm
End Property
Property Get MyParentForm() As Form_MyMainFormName
Set MyParentForm = cvMyParentForm
End Property
Private Sub cvMyParentForm_Current()
'MsgBox "Sub form current event - does syncing"
Me.Form.Recordset.FindFirst "ID = " & Nz(cvMyParentForm.ID, 0)
If Me.Form.Recordset.NoMatch Then
MsgBox "Humph"
Else
End If
End Sub
Private Sub cvMyParentForm_MyEvent()
MsgBox "A user define event 'MyEvent' was fired on the main form"
End Sub