I have a table that stores data entered by a user in a form. All of the data entered in the form saves properly in the table except for those fields chosen from a combo box. I have checked to make sure that all of these combo box selections in the Form Design View are bound to the associated table fields in the underlying data.
Currently, I have the data type for those fields in the design view of the table set as "Short Text". I am wondering if the problem is that I need to set the data type to a different type, or if there is something else causing this problem.
Option Compare Database
Option Explicit
Dim stay As String
Function EnableInfo()
Me.ADescription.Locked = False
Me.ComboVendor.Locked = False
Me.ComboVendor.Locked = False
Me.onHand.Locked = False
Me.onOrder.Locked = False
Me.CostB.Locked = False
Me.ListPriceB.Locked = False
End Function
Function DisableInfo()
Me.ADescription.Locked = True
Me.ComboVendor.Locked = True
Me.onHand.Locked = True
Me.onOrder.Locked = True
Me.CostB.Locked = True
Me.ListPriceB.Locked = True
End Function
'------------------------------------------------------------
' Function that disables/enable when command buttons when ADD and Edit are clicked!
'------------------------------------------------------------
Function AddEdit()
Me.CmdAdd.Enabled = False
Me.CmdEdit.Enabled = False
Me.CmdExit.Enabled = False
Me.CmdSave.Enabled = True
Me.CmdCancel.Enabled = True
Me.AllowAdditions = True
Me.AllowDeletions = True
Me.AllowEdits = True
Call EnableInfo
End Function
'------------------------------------------------------------
' Function that disables/enable when command buttons when Save and Cancel are clicked!
'------------------------------------------------------------
Function SaveCancel()
Me.CmdAdd.Enabled = True
Me.CmdEdit.Enabled = True
Me.CmdExit.Enabled = True
Me.CmdSave.Enabled = False
Me.CmdCancel.Enabled = False
Call DisableInfo
End Function
'------------------------------------------------------------
' Function that enables navigation buttons
'------------------------------------------------------------
Function EnableNavigation()
Me.cmdFirst.Enabled = True
Me.cmdNext.Enabled = True
Me.cmdPrevious.Enabled = True
Me.cmdlast.Enabled = True
End Function
'------------------------------------------------------------
' Function that disables navigation buttons
'------------------------------------------------------------
Function DisableNavigation()
Me.cmdFirst.Enabled = False
Me.cmdNext.Enabled = False
Me.cmdPrevious.Enabled = False
Me.cmdlast.Enabled = False
End Function
'------------------------------------------------------------
' Function when the ADD button is clicked
'------------------------------------------------------------
Private Sub CmdAdd_Click()
PartIDtext.SetFocus
stay = PartIDtext.Value
Me.DataEntry = True
Call EnableInfo
Call AddEdit
Call DisableNavigation
End Sub
'------------------------------------------------------------
' Function when the CANCEL button is clicked
'------------------------------------------------------------
Private Sub CmdCancel_Click()
Call SaveCancel
Call DisableInfo
Call EnableNavigation
Me.Undo
Me.DataEntry = False
Me.RecordsetClone.FindFirst "partID = " & stay
Me.Bookmark = Me.RecordsetClone.Bookmark
End Sub
'------------------------------------------------------------
' Function when the EDIT button is clicked
'------------------------------------------------------------
Private Sub CmdEdit_Click()
Call AddEdit
Call EnableInfo
Call DisableNavigation
PartIDtext.SetFocus
stay = PartIDtext.Value
End Sub
'------------------------------------------------------------
' Function when the EXIT button is clicked
'------------------------------------------------------------
Private Sub CmdExit_Click()
DoCmd.Close
End Sub
'------------------------------------------------------------
' Function when the SAVE button is clicked
'------------------------------------------------------------
Private Sub CmdSave_Click()
ADescription = Trim(ADescription.Value)
stay = Me.PartIDtext.Value
If IsNull(Me.ADescription) Or Len(Me.ADescription) < 5 Then
MsgBox "Please enter a description of at least 5 characters"
Me.ADescription.SetFocus
ElseIf IsNull(Me.onHand) Or (Me.onHand) < 0 Then
MsgBox "On hand must have a value greater than 0"
Me.onHand.SetFocus
ElseIf IsNull(Me.ComboVendor) Then
MsgBox "select one"
Me.onHand.SetFocus
ElseIf IsNull(Me.onOrder) Or (Me.onOrder) < 0 Then
MsgBox "On order must have a value greater than 0"
Me.onOrder.SetFocus
ElseIf IsNull(Me.CostB) Or (Me.CostB) < 0 Then
MsgBox "Cost must have a value greater than 0"
Me.CostB.SetFocus
ElseIf IsNull(Me.ListPriceB) Or (Me.ListPriceB) < (Me.CostB) Then
MsgBox "List price must be greater than cost!"
Me.ListPriceB.SetFocus
Else
Me.DataEntry = False
Me.RecordsetClone.FindFirst "partID = " & stay
Me.Bookmark = Me.RecordsetClone.Bookmark
Call SaveCancel
Call DisableInfo
Call EnableNavigation
End If
End Sub
'------------------------------------------------------------
' CmdNext
'------------------------------------------------------------
Private Sub CmdNext_Click()
On Error Resume Next
DoCmd.GoToRecord , "", acNext
End Sub
'------------------------------------------------------------
' CmdPrevious
'------------------------------------------------------------
Private Sub CmdPrevious_Click()
On Error Resume Next
DoCmd.GoToRecord , "", acPrevious
End Sub
'------------------------------------------------------------
' CmdFirst
'------------------------------------------------------------
Private Sub CmdFirst_Click()
DoCmd.GoToRecord , "", acFirst
End Sub
'------------------------------------------------------------
' CmdLast
'------------------------------------------------------------
Private Sub CmdLast_Click()
DoCmd.GoToRecord , "", acLast
End Sub
Related
I've got a MS Access form with a sub-form which I want to be read-only for existing records to prevent accidental changes. I've done this by putting simple code on both forms:
Private Sub Form_Current()
Me.AllowEdits = False
Me.AllowDeletions = False
Me.AllowAdditions = False
End Sub
I also added a button that changes the form to allow edits:
Private Sub Command110_Click()
Me.AllowEdits = True
Me.AllowDeletions = True
Me.AllowAdditions = True
End Sub
So I can then edit the form. However I have a button on the parent form to create a new record. I used the standard button function builder "Record Operations -> Add New Record" to create this button. But when I try to use it the error says: Error - You Can't Go To The Specified Record.
So I created a new button with this code:
Private Sub NewClientButton_Click()
Me.AllowEdits = True
Me.AllowDeletions = True
Me.AllowAdditions = True
DoCmd.GoToRecord , , acNewRec
End Sub
Thinking that would solve it but I still get an error: Runtime Error 2105 You can't Go To Specified Record.
The code on my form in totality looks like this:
Private Sub Command110_Click()
Me.AllowEdits = True
Me.AllowDeletions = True
Me.AllowAdditions = True
End Sub
Private Sub Form_Current()
Me.AllowEdits = False
Me.AllowDeletions = False
Me.AllowAdditions = False
End Sub
Private Sub NewClientButton_Click()
Me.AllowEdits = True
Me.AllowDeletions = True
Me.AllowAdditions = True
DoCmd.GoToRecord , , acNewRec
End Sub
Is it just the ordering of my code subs that is the problem or something else?
Thanks.
I have created a login form with a combo box for the user type (Admin, User) and a text box for the password. The code for the form is as follows.
Private Sub txtPassword_AfterUpdate()
If IsNull(Me.cboUser) Then
MsgBox "You need to select a user!", vbCritical
Me.cboUser.SetFocus
Else
If Me.txtPassword = Me.cboUser.Column(2) Then
If Me.cboUser.Column(3) = True Then
MsgBox "Password does not match, please re-enter!", vboOkOnly
Me.txtPassword = Null
Me.txtPassword.SetFocus
End If
DoCmd.OpenForm "FE1"
Me.Visible = False
Else
MsgBox "Password does not match, please re-enter!", vboOkOnly
Me.txtPassword = Null
Me.txtPassword.SetFocus
End If
End If
End Sub
Private Sub cboUser_AfterUpdate()
Forms!frmLogin!cboUser.Column (2)
End Sub
If the log in is as a User, when they get to the FE1 form, I want them just to be able to read the form, and not make any changes. The code I've been trying to use for this is as follows:
Private Sub Form_Open()
If Forms!frmLogin!cboUser.Column(2) = 2 Then
Me.AllowEdits = False
Me.AllowAdditions = False
Me.AllowDeletes = False
Else
Me.AllowEdits = True
Me.AllowAdditions = True
Me.AllowDeletes = True
End If
End Sub
But I keep getting the error:
The expression On Open you entered as the event property setting
produced the following error: Procedure declaration does not
match description of event or procedure having the same name.
*The expression may not result in the name of a macro, the name of a user-defined function, or [Event Procedure].
*There may have been an error evaluating the function, event, or macro.
It's possible I've just been looking at this for too long, but I can't figure out where I've gone wrong!?
Your Form_Open procedure has the wrong signature, missing the Cancel parameter.
It must be:
Private Sub Form_Open(Cancel As Integer)
Don't write event procedures by hand, let Access create them.
Edit
I suggest you completely remove the Form_Open sub. Then let Access create it from the property sheet.
And you can simplify your code by using a variable like this:
Private Sub Form_Open(Cancel As Integer)
Dim AllowWriting As Boolean
AllowWriting = Not (Forms!frmLogin!cboUser.Column(2) = 2)
Me.AllowEdits = AllowWriting
Me.AllowAdditions = AllowWriting
Me.AllowDeletes = AllowWriting
End Sub
or even shorter with the RecordsetType Property:
Private Sub Form_Open(Cancel As Integer)
If Forms!frmLogin!cboUser.Column(2) = 2 Then
Me.RecordsetType = 2 ' Snapshot = read-only
Else
Me.RecordsetType = 0 ' Dynaset = read-write
End If
End Sub
My intent is to deny users that do not meet a certain access level access to forms. I initially had issues with error code 3265 while writing the code for:
TempVars("EmployeeType").Value = rs!EmployeeType_ID.Value
This is no longer an issue; however, I cannot get access to the form even when the appropriate user is trying to enter. I've checked the spelling of table and column names multiple times as well.
Below is my code for the login (where I'm using the tempvars), followed by the code in form Load().
Option Compare Database
Option Explicit
Private Sub btnLogin_Click()
Dim rs As Recordset
Set rs = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot, dbReadOnly)
rs.FindFirst "UserName='" & Me.txtUserName & "'"
If rs.NoMatch = True Then
Me.lblWrongUser.Visible = True
Me.txtUserName.SetFocus
Exit Sub
End If
Me.lblWrongUser.Visible = False
If rs!Password <> Me.txtPassword Then
Me.lblWrongPass.Visible = True
Me.txtPassword.SetFocus
Exit Sub
End If
If IsNull(Me.txtUserName) Or IsNull(Me.txtPassword) Then
MsgBox "You must enter password or login ID.", vbOKOnly + vbInformation, "Required Data"
Me.txtUserName.SetFocus
Exit Sub
End If
Me.lblWrongPass.Visible = False
If rs!EmployeeType >= 4 Then
Dim prop As Property
On Error GoTo SetProperty
Set prop = CurrentDb.CreateProperty("AllowBypassKey", dbBoolean, False)
TempVars("UserName").Value = Me.txtUserName.Value
TempVars("EmployeeType").Value = rs!EmployeeType_ID.Value
CurrentDb.Properties.Append prop
SetProperty:
If MsgBox("Would you like to turn on the bypass key?", vbYesNo, "Allow Bypass") = vbYes Then
CurrentDb.Properties("AllowBypassKey") = True
Else
CurrentDb.Properties("AllowBypassKey") = False
End If
End If
Me.Visible = False
DoCmd.OpenForm "frmMain"
Globals.LoggingSignOn "Logon"
End Sub
Private Sub Form_Load()
Me.txtUserName = Null
Me.txtPassword = Null
Me.txtUserName.SetFocus
End Sub
Private Sub Form_Unload(Cancel As Integer)
Globals.LoggingSignOn "Logoff"
End Sub
Private Sub Form_Load()
If Nz(DLookup("HasAccess", "tbl9EmployeeAccess", "EmployeeType_ID=" & TempVars("EmployeeType") & " FormName='" & Me.Name & "'"), False) = False Then
MsgBox "You do not have access to access this location."
DoCmd.Close acForm, Me.Name
End If
End Sub
Thank you for your time, to anybody that looks into this.
I'm working with MS Access 2007. I have an event mapped to a command button, which works as expected when it's clicked. I've also added an ampersand in the caption field for the button command, so users can use shortcut keys (in this case alt+s) to also fire the event.
Here is the command that's executed when the command button is clicked or, depending on which fields are in focus, alt+s is pressed:
Private Sub cmdSearch_Click()
If cmdSearch.Caption = "&Search Mode" Then
cmdDelete.Enabled = False
cmdGotoNew.Enabled = False
cmdMenu.Enabled = False
cmdLicHistory.Enabled = False
cmdComplaints.Enabled = False
cmdAddPrint.Enabled = False
cmdReceipts.Enabled = False
cmdLicensee.Enabled = False
cmdSearch.Caption = "Run &Search"
Me.Filter = "1 = 0"
Me.FilterOn = True
DoCmd.GoToRecord acDataForm, "frmLicense", acNewRec
Detail.BackColor = 12615808
Else
Dim cntrl As Control
Dim strFilter As String
For Each cntrl In Me.Controls
If TypeName(cntrl) = "Textbox" Or TypeName(cntrl) = "Combobox" Then
If Not Len(cntrl) = 0 Then
If Not Len(strFilter) = 0 Then strFilter = strFilter & "and "
strFilter = strFilter & cntrl.ControlSource & " like '*" & cntrl & "*' "
End If
End If
Next
If Not Len(strFilter) = 0 Then
DoCmd.DoMenuItem acFormBar, acEditMenu, acUndo, , acMenuVer70
End If
Me.Filter = strFilter
Me.FilterOn = True
DoCmd.GoToRecord acDataForm, "frmLicense", acFirst
cmdDelete.Enabled = True
cmdGotoNew.Enabled = True
cmdMenu.Enabled = True
cmdLicHistory.Enabled = True
cmdComplaints.Enabled = True
cmdAddPrint.Enabled = True
cmdReceipts.Enabled = True
cmdLicensee.Enabled = True
cmdSearch.Caption = "&Search Mode"
' Detail.BackColor = 12632256
Detail.BackColor = -2147483633 ' Grey
End If
End Sub
However, depending on which fields are in focus, the shortcut keys will fire or not fire. Fields that nested in option groups will fire; fields nested in a tab control will not fire.
Is this behavior expected? This is a form level event, so I'm inclined to say that it's not. Any advice on debugging this would be appreciated.
When my database is opened, it shows a form with a "loading bar" that reports the progress of linking external tables and such, before showing a "Main Menu" form. The Main Menu has code that generates a form programmatically behind the scenes with buttons on it, and when that's done it saves and renames the form, and assigns it as the SourceObject to a subform.
This all works fine and dandy, that is, until I decide to make the buttons actually do something useful. In the loop that generates the buttons, it adds VBA code to the subform-to-be's module. For some reason, doing that makes VBA finish execution, then stop. This makes the (modal) loading form not disappear as there's an If statement that executes a DoCmd.Close to close the loading form when it's done loading. It also breaks functionality that depends on a global variable being set, since the global is cleared when execution halts.
Is there a better way to go about creating buttons that do stuff programmatically, short of ditching Access outright and writing real code? As much as I would love to, I'm forced to do it in Access in case I leave the company so the less tech-savvy employees can still work with it in my absence.
Below are bits and pieces of relevant code, if needed.
Form_USysSplash:
'Code that runs when the form is opened, before any processing.
Private Sub Form_Open(Cancel As Integer)
'Don't mess with things you shouldn't be.
If g_database_loaded Then
MsgBox "Please don't try to run the Splash form directly.", vbOKOnly, "No Touching"
Cancel = True
Exit Sub
End If
'Check if the user has the MySQL 5.1 ODBC driver installed.
Call CheckMysqlODBC 'Uses elfin majykks to find if Connector/ODBC is installed, puts the result into g_mysql_installed
If Not g_mysql_installed Then
Cancel = True
DoCmd.OpenForm "Main"
Exit Sub
End If
End Sub
'Code that runs when the form is ready to render.
Private Sub Form_Current()
'Prepare the form
boxProgressBar.width = 0
lblLoading.caption = ""
'Render the form
DoCmd.SelectObject acForm, Me.name
Me.Repaint
DoEvents
'Start the work
LinkOMTables
UpdateStatus "Done!"
DoCmd.OpenForm "Home"
f_done = True
End Sub
Private Sub Form_Timer() 'Timer property set to 100
If f_done Then DoCmd.Close acForm, Me.name
End Sub
Form_Home:
'Code run before the form is displayed.
Private Sub Form_Load()
'Check if the user has the MySQL 5.1 ODBC driver installed.
'Header contains an error message and a download link
If Not g_mysql_installed Then
FormHeader.Visible = True
Detail.Visible = False
Else
FormHeader.Visible = False
Detail.Visible = True
CreateButtonList Me, Me.subTasks
End If
End Sub
'Sub to create buttons on the form's Detail section, starting at a given height from the top.
Sub CreateButtonList(ByRef frm As Form, ByRef buttonPane As SubForm)
Dim rsButtons As Recordset
Dim newForm As Form
Dim newButton As CommandButton
Dim colCount As Integer, rowCount As Integer, curCol As Integer, curRow As Integer
Dim newFormWidth As Integer
Dim taskFormName As String, newFormName As String
Set rsButtons = CurrentDb.OpenRecordset("SELECT * FROM USysButtons WHERE form LIKE '" & frm.name & "'")
If Not rsButtons.EOF And Not rsButtons.BOF Then
taskFormName = "USys" & frm.name & "Tasks"
On Error Resume Next
If TypeOf CurrentProject.AllForms(taskFormName) Is AccessObject Then
buttonPane.SourceObject = ""
DoCmd.DeleteObject acForm, taskFormName
End If
Err.Clear
On Error GoTo 0
Set newForm = CreateForm
newFormName = newForm.name
With newForm
.Visible = False
.NavigationButtons = False
.RecordSelectors = False
.CloseButton = False
.ControlBox = False
.width = buttonPane.width
.HasModule = True
End With
rsButtons.MoveLast
rsButtons.MoveFirst
colCount = Int((buttonPane.width) / 1584) 'Twips: 1440 in an inch. 1584 twips = 1.1"
rowCount = Round(rsButtons.RecordCount / colCount, 0)
newForm.Detail.height = rowCount * 1584
curCol = 0
curRow = 0
Do While Not rsButtons.EOF
Set newButton = CreateControl(newForm.name, acCommandButton)
With newButton
.name = "gbtn_" & rsButtons!btn_name
.Visible = True
.Enabled = True
.caption = rsButtons!caption
.PictureType = 2
.Picture = rsButtons!img_name
.PictureCaptionArrangement = acBottom
.ControlTipText = rsButtons!tooltip
.OnClick = "[Event Procedure]"
'This If block is the source of my headache.
If Not IsNull(rsButtons!open_query) And rsButtons!open_query <> "" Then
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"Private Sub gbtn_" & rsButtons!btn_name & "_Click()"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"DoCmd.OpenQuery """ & rsButtons!open_query & """"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"End Sub" & vbCrLf & vbCrLf
ElseIf Not IsNull(rsButtons!open_form) And rsButtons!open_form <> "" Then
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"Private Sub gbtn_" & rsButtons!btn_name & "_Click()"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"DoCmd.OpenForm """ & rsButtons!open_form & """"
newForm.Module.InsertLines newForm.Module.CountOfLines, _
"End Sub" & vbCrLf & vbCrLf
End If
.height = 1584
.width = 1584
.Top = 12 + (curRow * 1584)
.Left = 12 + (curCol * 1584)
.BackThemeColorIndex = 1
.HoverThemeColorIndex = 4 'Accent 1
.HoverShade = 0
.HoverTint = 40 '60% Lighter
.PressedThemeColorIndex = 4 'Accent 1
.PressedShade = 0
.PressedTint = 20 '80% Lighter
End With
curCol = curCol + 1
If curCol = colCount Then
curCol = 0
curRow = curRow + 1
End If
rsButtons.MoveNext
Loop
DoCmd.Close acForm, newForm.name, acSaveYes
DoCmd.Rename taskFormName, acForm, newFormName
buttonPane.SourceObject = taskFormName
End If
End Sub
There is no need to write code while code is running, especially as you are writing essentially the same code over and over again. All you need do is call a function instead of an event procedure.
In your code above write the OnClick event like this:
If Not IsNull(rsButtons!open_query) And rsButtons!open_query <> "" Then
.OnClick = "=MyOpenForm(""" & rsButtons!open_form & """)"
ElseIf Not IsNull(rsButtons!open_form) And rsButtons!open_form <> "" Then
.OnClick = "=MyOpenQuery(""" & rsButtons!open_form & """)"
End If
Then create these two permanent (non-generated) functions somewhere the form can see them:
Public Function MyOpenForm(FormName as String)
DoCmd.OpenForm FormName
End Function
Public Function MyOpenQuery(QueryName as String)
DoCmd.OpenQuery QueryName
End Function
And ditch the code writing to the module.