Completely new to MS Access - I'm trying to do a simple modification to the MS Access Lending Library template using VBA.
Going into the Asset List form and clicking New Asset pops up the Asset Details form, where I can click the Save and New button. This calls the VBA code cmdSaveandNew_Click().
My question is, within this VBA method, how do I reference the values of the fields in the Asset Details form - For example getting the value that the user entered in the Category field and storing it in a variable.
I've tried several strings of code to try to get the value back, but I keep getting various errors, saying it can't find the referenced form, or Object Required, or this method is supported. I think it's likely just that I don't fully understand the structure of what I'm trying to reference or the syntax for specifying how to reference it.
Right now (after I've been trying many different combinations of things, I have:
text = Forms![Asset List].[Asset Details].Form.Category
which is giving me the "can't find the field '|1' referred to in your expression" error.
Edit - code currently looks like this:
Private Sub cmdSaveandNew_Click()
'On Error GoTo cmdSaveandNew_Click_Err
Dim someVar As String
Dim num As Integer
Dim objtf
'objtf = Forms![Asset List].[Asset Details].Form.Category
objtf = Me.Category
'num = Form.Controls.Count
Msg.Box (TypeName(objtf))
someVar = InputBox("How many?")
On Error Resume Next
If (Form.Dirty) Then
DoCmd.RunCommand acCmdSaveRecord
End If
If (MacroError.Number <> 0) Then
Beep
MsgBox MacroError.Description, vbOKOnly, ""
Exit Sub
End If
On Error GoTo 0
DoCmd.GoToRecord , "", acNewRec
DoCmd.GoToControl "Item"
MsgBox someVar
cmdSaveandNew_Click_Exit:
Exit Sub
cmdSaveandNew_Click_Err:
MsgBox Error$
Resume cmdSaveandNew_Click_Exit
End Sub
The variable must be declared global in a general module if you want to reference from various modules. Then setting it by code behind the Asset Details form would be simply: SomeVariableName = Me.Category.
Don't use reserved words as names - text is a reserved word.
Related
I have an error log that logs in the access table whenever a runtime error occurs for a user in the error trapper, and a particular error seems to occur for 10 random users, every hour at least.
This error appears to occur completely at random, on a random module with the Set ActiveForm code, with random users at random intervals. As far as I can see, there is no pattern between the users.
2475 - "You entered an expression that requires a form to be the active window".
This appears to occur in any of the modules that contain any of the setting of a form. I am using the following lines:
Dim af as Object
Set af = Screen.ActiveForm
I have tried using alternatives, such as declaring it as Form, and also tried the below:
Dim sstatus as String
Dim ps as String
If DLookup("[TM_UserType]", "[SD_Teams]", "[TM_username]= '" & usernm & "'") = "adj" Then
sstatus = "adj"
Else
sstatus = "tm"
End If
ps = "frmProdSubmit_" & sstatus
Then referencing the form this way:
Forms(ps).cmbTeam.Value = ""
But this still causes the same issue, even removing the ActiveForm part.
The last thing to mention (as I believe they could be factors) is that the front end is accessed through a shortcut, which minimises the Access window. Not sure if this could be the culprit, or if the user clicking another application can remove the focus.
The back-end of the database is also accessed by up to around 700 users each day.
As it stands, the error trapper pops up with the message, but the front end continues working correctly. It's just an annoying issue to resolve, but am slowly running out of ideas now, and any help would be hugely appreciated!
Error 2475 is thrown when a non-form object is the active screen object such as a table datasheet. I've encountered this error in an application that uses multiple instances of a form and needs to track whether the multiple form module is active or one of the other application module functions in which case all instances of the multiple forms (popups) need to have .visible set to false. I use the Screen.ActiveForm.Name call in the Form_Deactivate event.
You can trap the error in the procedure's error handler and take action knowing the screen's active object is not a form.
Example:
Private Sub Form_Deactivate()
On Error GoTo errHandler
If Screen.ActiveForm.Name <> "AnApplicationForm" Then 'throws 2475 if not a form object
sstatus = "status message"
End If
ExitSub:
Exit Sub
errHandler:
If Err.Number = 2475 Then Resume Next 'screen active object is not a form i.e. datasheet
MsgBox "Error in " & Me.Name & ".Form_Deactivate: " & Err.Number & " - " & Err.Description
Resume ExitSub
End Sub 'Form_Deactivate
Hoping to get more information on what column, table or row is causing a write conflict in a MS Access 2010 project, I wrote the following code:
Private Sub Form_BeforeInsert(Cancel As Integer)
Call printCollisionInfo(Me.Recordset, Me.name)
End Sub
Private Sub Form_BeforeUpdate(Cancel As Integer)
Call printCollisionInfo(Me.Recordset, Me.name)
End Sub
Method printCollisionInfo is:
Public Sub printCollisionInfo(rst As Recordset, formName As String)
Dim msg As String
msg = Now & " From " & formName & ": " & rst.BatchCollisionCount & " collisions"
Debug.Print msg
End Sub
But when calling rst.BatchCollisionCount, I get
"Operation is not supported for this type of object"
Is it because a form does not perform a dbUpdateBatch but some other type of update? Can I set the form's update type? Is there another way to see the SQL (with data values) or data that triggered the conflict?
The Recordset.BatchCollisionCount property is only valid for ODBCDirect workspaces.
This is stated in the Access 2010 online help, but unfortunately not on the MSDN page:
https://msdn.microsoft.com/en-us/library/office/ff198240(v=office.14).aspx
Look at how the recordset is set up in the example on that page. This is about as far from a bound form's recordset as it can be.
Here is an intro about ODBCDirect: http://www.avdf.com/may97/art_optimist.html
This technique is old, but the fact, that your question is #11 on my google search, gives you a hint about how many people use it...
I suggest a new question where you describe your setup and the error(s) you get.
I have a main form named Calling. It has a button named Travel. That Travel button does:
Private Sub btnTravel_Click()
On Error GoTo btnTravel_Click_Err
DoCmd.OpenForm "Travel", acNormal, "", "", acFormEdit
'If you can find a cleaner way to open a form I will be thankful.
btnTravel_Click_Exit:
Exit Sub
btnTravel_Click_Err:
MsgBox Error$
Resume btnTravel_Click_Exit
End Sub
The Travel info form performs correctly. That Travel form has a Close button with the code:
Private Sub bntClose_Click()
Unload Me
End Sub
When pressed, the Close code generates "Run-time error '361': Can't load or unload this object.
Your help is much appreciated.
You do not need the commas with the empty strings, nor do you need the acFormEdit as when you open the form you will be able to edit and add new records anyway.
If you leave this argument blank the form will open in the data mode set by the forms AllowEdits, AllowDeletions, AllowAdditions, and DataEntry permissions (in the form properties).
DoCmd.OpenForm "Travel", acNormal
As for the next sub routine, I would use docmd.close instead of unload.
Private Sub bntClose_Click()
Me.Undo
DoCmd.Close acForm, "Travel", acSaveNo
End Sub
The me.undo is optional, if you don't want to save, and if you want to save the form change the acSaveNo to acSaveYes.
EDIT:
I have just re-read your question and noticed in the title you want to do this without docmd.
I have had a think about this and docmd is the standard way of closing forms in access using VBA. I am not sure if you have inherited the unload from using VB, but I would stick to docmd.close when using access.
"Unolad me" just doesn't work in Access Form objects.
Access wants you to use DoCmd.Open/DoCmd.Close but you are clever than that and can use Access Form Object as an object. Access names the Form Classes prefixed the name you give them with "Form_". You create a Form named "YourForm", Access create the Class "Form_YourForm". Use this class as a real object:
'Declare a typed variable
Dim f As Form_YourForm
'Create the object
Set f = New Form_YourForm 'This triggers the Open event
'Use the object
f.SetFocus
f.Resize
'... And eventually, dispose the object
Set f = Nothing
'Remember <<Unload f>> won't work, neither you can use DoCmd.Close
Also, you can use Form_YourForm directly as an object variable because VBA Access just create "implicitly" this object out of the class Form_YourForm when you first use it or when you use DoCmd.Open. (Yes, it's a little bit confusing, but Access was create for users that didn't have necessarily programmer skills).
However, you'll get a different instance of the Form_YourForm Class each time you use a variable object typed as any of the Form Class that exist in your project. This means you can open as many instances of a form as you want ...or while it fits your computer's memory. You can't acomplish it using DoCmd.Open.
The main "disadvantages" are that you have to handle the form object from another module. You can still use the "Forms" collection but since you don't know the given key you can't reach your form instance easily. Also, you can't close the form from its own code, but only disposing the typed variable (Set f=nothing).
I have multiple fields on a form that have no values associated with them until data is entered into that field. At which point those controls have the #Name? value. All I'm trying to do is hide the fields using a loop as opposed to writing If statements. Here is the code working with a single If statement to hide said field/fields.
If Not Me.txtField.ControlSource = "#Name?" Then
Me.txtField.ColumnHidden = True
End If
I can't seem to figure out how to hide multiple controls that have the #Name? flag. Any help would be appreciated.
Dim ctl As Control
Dim ctlError As String
ctlError = "#Name?"
For Each ctl In Me.Controls
If Not ctl.ItemsSelected(txtField) = ctlError Then
ctl.ColumnHidden = True
End If
Next ctl
EDIT:
On the main form there is a subform with a cross tab query. But the problem is results on the query are populated from a combobox. So I've added fields that are not yet available in the query to the subform and end up with #Name? Attached is a screenshot to better illustrate the issue.
There is a 90% chance I'm going about this process wrong, so it's a learning process right now.
It would be easier to address this question if you described the specific errors that are raised by your code. This answer assumes that the control in question is a TextBox.
"#Name?" means that a control's ControlSource refers to a field that is not in the form's RecordSource. For example, if your query has two fields (ID and BirthDate, for example) and your form has three controls, with ControlSource of "ID", "BirthDate", and "BirthCountry", then the control whose RecordSource is "BirthCountry" will show "#Name?". However, its Value is not "#Name?". Rather, calling the Value property raises error 2424 (with the rather unhelpful message "The expression you entered has a field, control, or property name that Microsoft Office Access can't find").
The only way I know to check for the string "#Name?" is through the control's Text property, which is only available when the control has the focus, so that's not much help. If you retrieve the value of the ControlSource property, you'll get "BirthCountry" (of course). So you could check all ControlSources on your form against the fields of the form's RecordsetClone (add error handling, please):
For Each ctl In Controls
If Not RecordSourceContains(ctl.ControlSource) Then
ctl.Visible = False
End If
Next
Function RecordSourceContains(strFieldName as String) As Boolean
Dim fld As Field
For Each fld In RecordsetClone.Fields
If fld.Name = strFieldName Then
RecordSourceContains = True
Exit For
End If
Next
End Function
You'll probably want to do some other bookkeeping. For example, you'd want to check for expression control sources (which begin with "=") because they won't be in the RecordSource. You'll also either need to handle error 438 (Object doesn't support this property or method) or check each control's type to make sure it has a ControlSource property.
In design view for the form, what does the field say for Control Source? It should be blank, meaning the form is unbound. If it's not, then that explains #Name.
More information: http://www.databasedev.co.uk/unbound-forms-add-data.html
Here is code I use to take care of that:
Sub setControl
'' You can use this in your loop
Call FieldEnable(subFrm, "boxQty", booSellSet)
End Sub
''----------------
Private Sub FieldEnable(subFrm As Access.Form, strCtlName As String, _
booEnableMe As Boolean)
On Error GoTo errHandler
subFrm(strCtlName).Enabled = booEnableMe
subFrm(strCtlName).Visible = booEnableMe
errExit:
Exit Sub
errHandler:
If Err.Number = 2164 Or Err.Number = 2165 Then ''control has the focus
Resume Next
Else
DoCmd.Hourglass False
Screen.Application.Echo True
MsgBox "Problem with control named " & strCtlName
Resume errExit
End If
End Sub
I have to adjust many fields on the form, so this is very reusable. I might be turning them "on" or "off"; this takes care of either. Let me know if you have questions.
It all boils down to this method for hiding the field:
Control.Enabled = False
Control.Visible = False
Delete the field Black from table.
And then make make again the Black field in your table.
I am trying to preview a report of the current tracking number which is on the main form(main form name is:frmReviewReleaseLogWrapper) by using a command button.
Each tracking number has different part numbers, so each tracking number has many records in the DB table (Depending upon the number of partnumbers, that is each partnumber has a record)
I wrote the following code and it is not working, It is just displaying report name and column names and not the records.
Code is as follows:
Private Sub Command225_Click()
On Error GoTo Err_Command225_Click
Dim stDocName As String
DoCmd.OpenReport "rptEventLog", acPreview, , "[TrackingNumber] = Forms!frmReviewReleaseLogWrapper"
Exit_Command225_Click:
Exit Sub
Err_Command225_Click:
MsgBox Err.Description
Resume Exit_Command225_Click
End Sub
What's the name of the control on the frmReviewReleaseLogWrapper form that contains the tracking number? You need to reference it in your OpenReport statement, like so:
DoCmd.OpenReport "rptEventLog", acPreview, , _
"[TrackingNumber] = Forms!frmReviewReleaseLogWrapper!txtField"
Incidentally, you might do better to give your command button a name that reflects its actual function, so it'll be easier to find later.