I need to set some buttons for RunTime users.
I was created USysRibbon table, inserted XML and tested via Database options. All works fine.
But I need load Custom ribbon via VBA custom function. This function will be executed via AutoExec macro (after user login and user id as temp variable is set).
Please help me to create simple VBA to call LoadCustomUI function and get XML from table (in that table is ID, RibbonName and RibbonXML) and apply to user interface.
Thank you.
I assume that you have created your ribbon table like this : http://www.accessribbon.de/en/?Access_-_Ribbons:Load_Ribbons_Into_The_Database:..._Using_The_System_Table_USysRibbons
Let's say:
your AutoExec macro execute the function Start_App()
You have in your table a record with RibbonName="MyRibbon1"
Create a module with the following code
' This variable handle your ribbon name, so if you have several Ribbons in your table, you adapt this constant to match the current Ribbon
Public Const APP_RIBBON As String = "MyRibbon1"
Public Function Start_app()
On Error GoTo Err_Handler
LoadRibbons
' do anything else you need in the Start_app
Exit_Sub:
Exit Function
Err_Handler:
If Err.Number > 0 Then
MsgBox Err.DESCRIPTION, vbExclamation, "An error " & Err.Number & " occured !"
Debug.Print Err.Number
Resume Exit_Sub
End If
End Function
Private Function LoadRibbons()
On Error GoTo Error1
Dim RS As dao.Recordset
Set RS = CurrentDB.OpenRecordset("SELECT * FROM USysRibbon ")
Do Until RS.EOF
If RS("RibbonName").value = APP_RIBBON Then
' Ribbon found: Load it and exit
Application.LoadCustomUI APP_RIBBON, RS("RibbonXML").value
Exit Do
End If
RS.MoveNext
Loop
Error1_Exit:
On Error Resume Next
RS.Close
Set RS = Nothing
Exit Function
Error1:
Select Case Err
Case 32609
' Ribbon already loaded, do nothing and exit
Case Else
MsgBox "Error: " & Err.Number & vbCrLf & Err.DESCRIPTION, vbCritical, "Error", Err.HelpFile, Err.HelpContext
End Select
Resume Error1_Exit
End Function
Note that you have an additional thing to do: the first time you run the code, the Ribbon will not show. You have to go in the options / current database and in the combo box Ribbon Name: select the ribbon. If you have run the code once, your MyRibbon1 should appear in the combo box
Related
Others have had issues with the MSACCESS.EXE process not closing (from Task Manager) when exiting their databases. Each of the posts I've read have had something to do with not properly closing recordset variables.
When I exit the database I'm working on, I notice the MSACCESS.EXE process moves from the "Apps" section to "Background Processes" in Win 10 Task Manager. This hung process continues to utilize RAM. I'm certain that I'm closing all recordset variables properly.
Through a lot of debugging, I figured out a simple way to replicate the problem:
Create two forms in a new Access database. Set the PopUp property to True for one of them and False for the other. Save the forms "PopUp" and "NoPopUp" and close the database.
Open Task Manager to view the processes running on your screen.
Open your Access database and open the NoPopUp form. Note the MSACCESS.EXE process under Apps.
Close your database. Note that MSACCESS.EXE is removed from your list of Processes (both under "Apps" and "Background Processes").
Now reopen your Access database and open form PopUp. Then close the database.
Note that the MSACCESS.EXE process moves from the "Apps" section to "Background Processes" and is still utilizing system memory.
Additional MSACCESS.EXE processes hang in Task Manager each time the database is closed after opening a form with its Pop-up property set to True.
My database uses a ton of Pop-up forms. How should I be closing my database so that these hung processes aren't stacking up? (I'm using Access 2013 in Windows 10.)
Thanks,
Sam
How are you closing your database now?
Can you change the command to call a function.
Then in that function call a routine that closes all open forms
You may have to add parameter to close without saving - depending on your results.
Function CloseAllOpenFrms()
On Error GoTo Error_Handler
Dim DbF As Access.Form
Dim DbO As Object
Set DbO = Application.Forms 'Collection of all the open forms
For Each DbF In DbO 'Loop all the forms
DoCmd.Close acForm, DbF.Name, acSaveNo
Next DbF
Error_Handler_Exit:
On Error Resume Next
Set DbF = Nothing
Set DbO = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occured." & vbCrLf & vbCrLf & _
"Error Number: " & Err.Number & vbCrLf & _
"Error Source: CloseAllOpenFrms" & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "An Error has Occured!"
Resume Error_Handler_Exit
End Function
From http://www.devhut.net/2015/02/17/ms-access-vba-close-all-open-forms/
Try this very basic example in a new sample database.
EDIT: Add a Sleep and DoEvents after every close form in case of caching/fast cpu getting ahead of code? Last attempt to fix weird issue.
In Module 1
Option Compare Database
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Function CloseAllOpenFrms()
On Error GoTo Error_Handler
Dim DbF As Access.Form
Dim DbO As Object
Set DbO = Application.Forms 'Collection of all the open forms
' Close all popups first
For Each DbF In DbO 'Loop all the forms
If DbF.PopUp Then
DoCmd.Close acForm, DbF.Name, acSaveNo
DoEvents
Sleep 1000
End If
Next DbF
' Close remaining forms
For Each DbF In DbO 'Loop all the forms
DoCmd.Close acForm, DbF.Name, acSaveNo
DoEvents
Sleep 1000
Next DbF
Application.Quit acQuitSaveNone
Error_Handler_Exit:
On Error Resume Next
Set DbF = Nothing
Set DbO = Nothing
Exit Function
Error_Handler:
MsgBox "Error closing : " & DbF.Name & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "Error closing form"
Resume Error_Handler_Exit
End Function
Create basic Form1 with two command buttons:
Command button Command1 (Caption= Open Popup Form)
Command button Command0 (Caption = Exit DB)
In Form1's form module paste text
'------------------------------------------------------------
' Command1_Click
'
'------------------------------------------------------------
Private Sub Command1_Click()
On Error GoTo Command1_Click_Err
CloseAllOpenFrms
Command1_Click_Exit:
Exit Sub
Command1_Click_Err:
MsgBox Error$
Resume Command1_Click_Exit
End Sub
'------------------------------------------------------------
' Command0_Click
'
'------------------------------------------------------------
Private Sub Command0_Click()
On Error GoTo Command0_Click_Err
DoCmd.OpenForm "Form2-popup", acNormal, "", "", , acWindowNormal
Command0_Click_Exit:
Exit Sub
Command0_Click_Err:
MsgBox Error$
Resume Command0_Click_Exit
End Sub
Create another form Form2-popup and set Popup property to true
Add command button Command1 with caption "Exit Form"
'------------------------------------------------------------
' Command1_Click
'
'------------------------------------------------------------
Private Sub Command1_Click()
On Error GoTo Command1_Click_Err
DoCmd.Close , ""
Command1_Click_Exit:
Exit Sub
Command1_Click_Err:
MsgBox Error$
Resume Command1_Click_Exit
End Sub
In Access 2007 My Error Trapping is set on Break on Unhandled Errors
I want the code to stop at the line where an error occurs and exit functions instead of resuming to the next line of code. However it doesn't seem to be working for me. I purposely created an error at line 6 to see if it would exit the function after this line but it only prompts the error handler message and continues to resume to the next line after error occured.
Here is my code:
GoToBackend():
'Go to current linked backend database
Private Function GoToBackend()
On Error GoTo BackendErrorHandler
'To update BEPath requires two sets of proc.
'Delete Exisiting
RunQuery "DeleteBEEPath" 'Here is where I created error by miss spelling it
'Insert Into
RunQuery "InsertBEPath"
'Prompt alert
MsgBox "Front end tables succesfully linked. Access now needs to run the backend database to complete the linking process. Please ensure macros/vba are enabled if prompted.", 48
Hyperlink.GoHyperlink (Hyperlink.PrepHyperlink(GetBackendPath))
ExitFunction:
Exit Function 'Why won't this exit the function?
BackendErrorHandler:
Dim Msg As String
Msg = Err.Number & ": " & Err.Description
MsgBox Msg
Resume ExitFunction
End Function
RunQuery():
'Run a given query name
Private Function RunQuery(qName As String)
On Error GoTo RunQueryErrorHandler
DoCmd.SetWarnings False
DoCmd.OpenQuery qName
DoCmd.SetWarnings True
ExitFunction:
Exit Function
RunQueryErrorHandler:
Dim Msg As String
Msg = Err.Number & ": " & Err.Description
MsgBox Msg
Resume ExitFunction
End Function
The error itself happens in your RunQuery function so the error is handled there. In there you say to display the message for the error with Msg = Err.Number & ": " & Err.Description so therefore it pops up and the error is considered "Handled" and the original function continues to run.
Your line here:
RunQuery "DeleteBEEPath"
Doesn't care what your string is, in its eyes you have properly provided it a string to pass onto the function. Once it enters the function that is where the actual error occurs. I haven't tested this but I believe if you turn off the error handling in your second function then the error handling in GoToBackend should handle it in the way you want it to. So your second function would be something like this:
Private Function RunQuery(qName As String)
DoCmd.SetWarnings False
DoCmd.OpenQuery qName
DoCmd.SetWarnings True
End Function
Once again I haven't really been able to test this but this should get you on the right path or perhaps if someone with some more experience is around they could provide a better answer than I.
I would also recommend putting DoCmd.SetWarnings (True) in your error handling, that way if the error occurs after you set the to false they will get turned back on.
Edit: I figured I would throw in my newly conceptualized function. (Untested)
Public Function RunSQLNoWarnings(strSQLQuery As String) As Boolean
On Error GoTo Err_Handler
DoCmd.SetWarnings (False)
DoCmd.RunSQL (strSQLQuery)
DoCmd.SetWarnings (True)
RunSQLNoWarnings = True
Exit_Handler:
Exit Function
Err_Handler:
DoCmd.SetWarnings (True)
Call LogError(Err.Number, Err.Description, strMODULE_NAME & ".RunSQLNoWarnings on SQL Query: " & strSQLQuery)
RunSQLNoWarnings = False
Resume Exit_Handler
End Function
I have a function that has been in use for a number of months that checks to see if the form that is going to be opened will actually have records to be viewed before opening it. Recently I decided to change from ACCDB to ACCDE for security purposes. After making the change over the function started throwing error 2450 "Microsoft Access cannot find the referenced form..." I can't seem to find anything of use online that could tell me what the cause of this error is and why it only happens with ACCDE.
On a side note I realize the inefficiency of the logic in this function, it's on my list.
Public Function ValidateFormToOpen(strFormName As String, strFilter As String, strFieldName As String) As Boolean
On Error GoTo Err_Handler
Dim intNumberOfRecords As Integer
'If the form is currently open count how many results will be shown
If CheckFormState(strFormName) Then
intNumberOfRecords = DCount(strFieldName, Access.Forms(strFormName).RecordSource, strFilter)
'If it is closed open it in a hidden state and then count how many records would be shown
Else
DoCmd.OpenForm strFormName, acDesign, "", strFilter, , acHidden
intNumberOfRecords = DCount(strFieldName, Access.Forms(strFormName).RecordSource, strFilter)
DoCmd.Close acForm, strFormName
End If
'If there were records that will be shown return true
If intNumberOfRecords > 0 Then
ValidateFormToOpen = True
Else
ValidateFormToOpen = False
End If
Exit_Handler:
Exit Function
Err_Handler:
Call LogError(Err.Number, Err.Description, strMODULE_NAME & ".ValidateFormToOpen on " & strFormName)
Resume Exit_Handler
End Function
This is the CheckFormState Code
Public Function CheckFormState(sFormName As String) As Boolean
On Error GoTo Err_Handler
If Access.Forms(sFormName).Visible = True Then
CheckFormState = True
End If
Exit_Handler:
Exit Function
Err_Handler:
CheckFormState = False
Resume Exit_Handler
End Function
An ACCDE format database restricts design capabilities in general. I think that may be why you get an error with this line:
DoCmd.OpenForm strFormName, acDesign, "", strFilter, , acHidden
However I'm not positive that is the complete explanation because when I attempt to open a form in Design View (DoCmd.OpenForm "Form1", acDesign) in my ACCDE database, Access gives me a different error message:
"The command you specified is not available in an .mde, .accde, or .ade database."
So I don't know what the solution is for your goal, but I believe it can not be based on opening a form in Design View.
I was recently given the task of creating a form that will autofill with the information from a table. The information the form autofills is selected using a primary key called ModID. I have a combo box that has a List of the ModIDs that are listed as Active.
SELECT ModID
FROM P_Review
WHERE Status = "Active"
Simple enough. I then have VBA code running on the event After Update. So after the value for the combo box is select or changed it will run this VBA code.
Option Compare Database
Option Explicit
Private Sub selectModID_AfterUpdate()
'Find the record that matches the control.
On Error GoTo ProcError
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID=" & Me.selectModID
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.RunCommand acCmdRecordsGoToNew
Me!localModID = Me.selectModID.Column(0)
End If
End With
ExitProc:
Exit Sub
ProcError:
MsgBox "Error: " & Err.Number & ". " & Err.Description
Resume ExitProc
End Sub
The code runs fine (I get no errors when I debug or run).
Now for the access text box. I would like to populate certain fields based off the variable localModID. I have a dlookup in a text box to find the information in the table P_Review.
=DLookUp("Threshold","P_Review","ModID =" & [localModID])
So the DlookUp should find the value for the column threshold, in the table P_Review, where the ModID in P_Review equals the localModID set in the VBA code. But when I go to form view and select a ModID I get the Error 3070: The Microsoft Access database engine does not recognize as a valid field name or expression. I did copy this code from another database we are already using but it fails in this new instance.
Private Sub ModID_AfterUpdate()
Dim rs As Object
Set rs = Me.RecordsetClone
With rs
.FindFirst "ModID='" & Me.ModID & "'"
If Not .NoMatch Then
Me.Bookmark = .Bookmark
Else
DoCmd.GoToRecord , , acNewRec
Me!ModID = Me.ModID
End If
End With
End Sub
This is the answer to question. I used this code to auto update.
Try
Forms!<whatever_this_form_name_is>![localModID]
in your DLOOKUP
Is it at all possible to detect an insert operation performed by a subform while still in the parent form?
To clarify: I have a series of forms for data entry, they each have a button for adding an entry to the appropriate table (using the data provided in the form). I am attempting to set each of them in turn to a subform in a 'wizard' parent form that will cycle through all the data entry forms.
My problem arises when it comes to switching between forms, as it became clear that the AfterInsert event in this parent form was not detecting the insert triggered by the form contained in the subform. I know I could move the trigger for the insert to a button in the parent form; however, to my knowledge, this would require setting the code for the click event for each of the buttons in the data entry forms as public so that they may be called from the parent form's code. I am leery to do this and was thus hoping for other options.
Create a public procedure in the parent form.
Public Sub Listener(ByVal pMsg As String)
MsgBox pMsg
End Sub
Then, in each of your subforms, call that procedure from After Insert.
Private Sub Form_AfterInsert()
Dim strMsg As String
strMsg = Me.Name & " inserted row."
Call Me.Parent.Listener(strMsg)
End Sub
If the subform may also be used stand-alone (without a parent), Me.Parent will throw error #2452, "The expression you entered has an invalid reference to the Parent property." You can create a separate function to check whether the current form has a parent, and base your code on the function's return value.
Private Sub Form_Open(Cancel As Integer)
Dim strPrompt As String
If HaveParentForm(Me) = True Then
strPrompt = "I am a subform to '" & _
Me.Parent.Name & "'."
Else
strPrompt = "I am a top level form."
End If
MsgBox strPrompt
End Sub
The function ...
Public Function HaveParentForm(ByRef frm As Form) As Boolean
Dim blnReturn As Boolean
Dim strMsg As String
On Error GoTo ErrorHandler
blnReturn = (Len(frm.Parent.Name) > 0)
ExitHere:
HaveParentForm = blnReturn
On Error GoTo 0
Exit Function
ErrorHandler:
Select Case Err.Number
Case 2452 ' The expression you entered has an invalid '
' reference to the Parent property. '
Case Else
strMsg = "Error " & Err.Number & " (" & Err.Description _
& ") in procedure HaveParentForm"
MsgBox strMsg
End Select
blnReturn = False
GoTo ExitHere
End Function