Im attempting to replace all my path constants in VBA with an administration table in my datatbase so users can change the location of folders and files without having to edit vba code.
the code is as follows
Private Sub Command8_Click()
Debug.Print DLookup("fsFileLink", "tblFileSystem", "fsFileName= 'TEMPLATES'")
MsgBox = DLookup("fsFileLink", "tblFileSystem", "fsFileName= 'TEMPLATES'")
End Sub
debug.print returns
C:\Users\... \templates\
but the msgbox returns the error "left must be variant or object".
How can I get my dlookup value as a string that I can display and edit in a text box?
Thank You
I'm using the below code:
Dim strCOCTemplate As String
strCOCTemplate = Nz(DLookup("fsFileLink", "tblFileSystem", "fsFileName= 'TEMPLATE_COC2'"), "none")
If strCOCTemplate = "none" Then Err.Raise Number:=11001, Description:=ERR_DESC_11001
Set docJobSpec = WordApp.Documents.Add(Template:=strCOCTemplate, NewTemplate:=True)
Dlookup returns a variant, but Template:= can't accept null values and throws an akward error. I compensated for this by using nz() function to return a string, and raised my own custom error to say the table couldn't find data
Related
I have a button on a form that grabs the value of the selected column (SFDC_InventoryID) from a subform datasheet located on the MainForm. SFDC_InventoryID is a text string.
When I attempt to pass this value to a function (called "SFDC"), I am seeing the "Invalid use of property" error. VB never gets to my function.
In my code snippet below, the msgbox does show the expected string value. When I point to a simple textbox control on the MainForm itself, I do not see the same error.
Any suggestions to correct?
Private Sub btnSFDCInventory_Click()
'MsgBox just to test...
MsgBox Forms!mainform!InventoryList_subform.Form!SFDC_InventoryID
If Nz(Trim(Forms!mainform!InventoryList_subform.Form!SFDC_InventoryID)) = 0 Then
MsgBox "No SFDC InventoryID to Display"
Else
SFDC Forms!mainform!InventoryList_subform.Form!SFDC_InventoryID '<< this line throws the error
End If
End Sub
Calls this function:
Public Function SFDC(SFDC_ID As String)
Dim strSFDC As String
strSFDC = "https://na79.salesforce.com/" & SFDC_ID
Application.FollowHyperlink strSFDC
End Function
Try this
If Nz(Trim(Forms!mainform!InventoryList_subform.Form!SFDC_InventoryID),"") = "" Then
MsgBox "No SFDC InventoryID to Display"
Else
SFDC Forms!mainform!InventoryList_subform.Form!SFDC_InventoryID
End If
I been working on the following code to when the user click on the button to save and go new record that Access locates the highest client id used by set location and then adds 1 to it. Prior to saving the record and moving on to new record. While work through other errors, but I can not get past error object required on this line. "Me.ClientID = IIf(DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'") Is Null, 0, DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'")) + 1"
The more i look at the similar questions more confused I get as to what is wrong with the code. Thank you in advance for any suggestions David
Private Sub Save_Record_Click()
'declare variables for default values
Dim defaultinterviewr As String
Dim defaultcorps As String
'Variables get their values
defaultinterviewr = Me.Interviewer.Value
defaultcorps = Me.Corps.Value
'Check to see if ClientID field is Blank.
If IsNull(Me.ClientID) Then
'Check that Corps field is filled in
If IsNull(Me.Corps) Then
MsgBox "Corps must be entered before saving record.", vbOKOnly
Me.Corps.SetFocus
'set client id base on corps by finding the highest id and adding 1 to that number
Else
Me.ClientID = IIf(DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'") Is Null, 0, DMax("[ClientID]", "tClientinfo", "[CorpsName]=" & "'defaultcorps'")) + 1
End If
End If
MsgBox "Done", vbOKOnly
'save record
'DoCmd.RunCommand acCmdSaveRecord
'Me.stateidnum1 = ""
'open new record
'DoCmd.GoToRecord , , acNewRec
'set field default value
'Me.Interviewer.Value = defaultinterviewr
'Me.Corps.Value = defaultcorps
'Me.Child_Subform.Form.AllowAdditions = True
End Sub
I think you need to start off by figuring out if your DMAX() statement is correctly producing results. The next thing I see and which is probably your main culprit is the fact that you are using the Expression IIf() inside VBA. The IIf() expression you are using will work inside a query or in a textbox but VBA has it's own If statement block which you are correctly using in the lines preceding it.
I would actually use the Nz Function to simplify it even more as follows:
UPDATED Based off of your comment below I re-looked at your overall code and noticed that "defaultcorps" is a variable and not a value I originally thought you were trying to filter by. You were wrapping the variable in quotes. My updated answer should work for you.
Me.ClientID = (Nz(DMax("[ClientID]", "tClientinfo", "[CorpsName]= '" & defaultcorps & "'"),0)+1)
Is it possible to increase the font size of message box in Access 2013 via vba code?
From this
to this
Some users are over 40 years old. They require a bigger size of font for viewing. Thanks!
The font size of system error boxes is a system control and would need to be changed on all individual computers.
You could instead trap the error in VBA and display your own messages via a UserForm, which would allow you to control the message and the font.
So, instead of
If countDuplicate > 0 Then
MsgBox _
"A record of this Part ID already exist. No changes can be made.", _
vbCritical, _
"Duplicated Record"
Me.Undo
End If
You would have the following:
If countDuplicate > 0 Then
frm_AlreadyExists.Show
Me.Undo
End If
Where frm_AlreadyExists is a form that you would create and would have the message you listed above.
That should get you started. As a further step, instead of having a separate UserForm for each error, you could create an error table that would contain Error ID, Error Message, Error Type, Error Title columns.
Error ID Error Message Error Type Error Title Button Action Button Text
1 A record ... already exist. Critical Duplicated Record SubName1 Click Here
2 ... not a valid EMPLOYEE Critical Invalid GID SubName2 Click Here
Then you would call the UserForm with the following:
If countDuplicate > 0 Then
ErrorID = 1 'You'll need to declare this variable elsewhere in your code
frm_AlreadyExists.Show
End If
And the code to initialize the UserForm (in the UserForm code module)
Private Sub UserForm_Initialize()
Dim lErrorID As Long
Dim sErrorMessage As String
Dim sErrorType As String
Dim sErrorTitle As String
Dim sBtnText As String
lErrorID = errorID
''Look up the following from the Error Table
'sErrorMessage = Result from lookup
'sErrorType = Result from lookup
'sErrorTitle = Result from lookup
'sBtnText = Result from lookup
Me.lbl_ErrorMessage = sErrorMessage
Me.img_ErrorType.Picture = "C:/File Location/" & sErrorType & ".jpg"
Me.Caption = sErrorTitle
Me.btn_Action.Caption = sBtnText
End Sub
And the code for the button click
Private Sub btn_Action_Click()
Dim sBtnAction As String
''Look up the following from the Error Table
'sBtnAction = Result from lookup
Application.Run sBtnAction
End Sub
With this and some tweaking and messing with code, you can now have a custom error/message system that would allow you (or even the user) to set the font for the messages.
I have created this function GetSubName that I need to return the name that is saves from a pull down box. It does this just fine as the dialog boxes I have used shows that it sets the variable correctly. The problem is that when the SQL below runs in a query I get the error: "Undefined function 'GetSubName' in expression." I am new to VBA so any help would be much appreciated.
Here is the code:
Option Compare Database
Option Explicit
Private stSubName As String
Private Sub Command2_Click()
On Error GoTo Err_Command2_Click
Dim stDocName As String
Dim stSubName As String
SubcontractorCombo.SetFocus
stSubName = SubcontractorCombo.SelText
'Confirm that stSubName variable is holding correct value'
MsgBox "Name of Subcontractor Selected is " & stSubName
SetSubName stSubName
GetSubName
DoCmd.Close
stDocName = "Summary Asphalt Production for Subcontractor"
DoCmd.OpenQuery stDocName
Exit_Command2_Click:
Exit Sub
Err_Command2_Click:
MsgBox Err.Description
Resume Exit_Command2_Click
End Sub
Public Sub SetSubName(Value As String)
'Set the module variable to be the value passed in from externally'
stSubName = Value
End Sub
Public Function GetSubName() As String
'Returns the value of the module variable'
GetSubName = stSubName
'MsgBox "GetSubName Variable is " & stSubName'
End Function
And here is my SQL from inside of Access 2007:
SELECT DISTINCTROW Subs.Subcontractor, Counties.County, Projects.ContractID,
Sum(Project_Items.USTons) AS SumOfUSTons, Projects.PlanQuantity,
Max(Project_Items.EstDate) AS MaxOfEstDate, Project_Items.Sub
FROM Counties INNER JOIN (Subs INNER JOIN (Projects INNER JOIN Project_Items ON
Projects.ContractID = Project_Items.ProjectID) ON Subs.VendID = Project_Items.Sub) ON
Counties.ID = Project_Items.County
WHERE (((Projects.Completed)<>True) AND ((Subs.Subcontractor)=GetSubName()))
GROUP BY Subs.Subcontractor, Counties.County, Projects.ContractID,
Projects.PlanQuantity, Project_Items.Sub;
The reason the functions are not recognized is that you haven't fully specified the name. A public function in a form module needs to be specified with the form name:
Forms!MyForm.GetSubName()
But this is the wrong approach, and your code is way too convoluted. You can access the value of the combo box in your query directly:
Forms!MyForm!SubcontractorCombo
Now, the fact that you're using .SelText suggests to me either that you're doing something very very tricky, or you have your combo box set up wrong. Combo boxes can have a found field and a display value, such that a list of employees might display the employee LastName/FirstName while the combo box actually has as its bound field the EmployeeID.
If your combo box has a hidden bound field, but you want the displayed value, you don't need to use .SelText -- just use the appropriate .Column() of the combo box:
Forms!MyForm!SubcontractorCombo.Column(1)
(the column count is zero-based, so the hidden column would be column 0, assuming it's the first column that is hidden)
Also, there's an issue that if the user selects PART of the text in the combo box, you'd have an incomplete match, so you really don't want to use .SelText at all.
So, the WHERE clause of your SQL would end up being this (assuming I've diagnosed everything correctly):
WHERE Projects.Completed<>True
AND Subs.Subcontractor=Forms!MyForm!SubcontractorCombo.Column(1)
...and you can lose all of the marked code:
Option Compare Database
Option Explicit
<strike>Private stSubName As String</strike>
Private Sub Command2_Click()
On Error GoTo Err_Command2_Click
Dim stDocName As String
Dim stSubName As String
SubcontractorCombo.SetFocus
<strike>stSubName = SubcontractorCombo.SelText</strike>
'Confirm that stSubName variable is holding correct value'
<strike>MsgBox "Name of Subcontractor Selected is " & stSubName</strike>
<strike>SetSubName stSubName</strike>
<strike>GetSubName</strike>
DoCmd.Close
stDocName = "Summary Asphalt Production for Subcontractor"
DoCmd.OpenQuery stDocName
Exit_Command2_Click:
Exit Sub
Err_Command2_Click:
MsgBox Err.Description
Resume Exit_Command2_Click
End Sub
<strike>Public Sub SetSubName(Value As String)
'Set the module variable to be the value passed in from externally'
stSubName = Value
End Sub</strike>
<strike>Public Function GetSubName() As String
'Returns the value of the module variable'
GetSubName = stSubName
'MsgBox "GetSubName Variable is " & stSubName'
End Function</strike>
Would an alternative approach work?
Create a table (SubNameTable) with one field: SubName.
Add one record to it.
Then change your Sub to this:
Public Sub SetSubName(Value As String)
CurrentDb.Execute ("Update SubNameTable Set SubName = '" & Value & "'")
End Sub
Now you can Remove the function and modular variable.
Then, alter your SQL as such:
SELECT
*BlahBlahBlahFields*
FROM
*BlahBlahBlahTables*
INNER JOIN Subs
INNER JOIN SubNameTable ON Subs.SubContractor = SubNameTable.SubName
WHERE (((Projects.Completed)<>True)
GROUP BY
Subs.Subcontractor,
Counties.County,
Projects.ContractID,
Projects.PlanQuantity,
Project_Items.Sub
Not that this is the greatest solution, but should solve some future problems of trying to reference a function in a form. You could use a parameter on your query and set its value to the combo box.
You should put the public functions in a Module. I called this one Module2
Option Compare Database
Option Explicit
Private stSubName As String
Public Sub SetSubName(Value As String)
'Set the module variable to be the value passed in from externally'
stSubName = Value
End Sub
Public Function GetSubName() As String
'Returns the value of the module variable'
GetSubName = stSubName
'MsgBox "GetSubName Variable is " & stSubName'
End Function
Your form will reference the functions in the module:
Option Compare Database
Option Explicit
Private stSubName As String
Private Sub Command2_Click()
On Error GoTo Err_Command2_Click
Dim stDocName As String
Dim stSubName As String
SubcontractorCombo.SetFocus
stSubName = SubcontractorCombo.SelText
'Confirm that stSubName variable is holding correct value'
MsgBox "Name of Subcontractor Selected is " & stSubName
Module2.SetSubName stSubName
Module2.GetSubName
DoCmd.Close
stDocName = "Summary Asphalt Production for Subcontractor"
DoCmd.OpenQuery stDocName
Exit_Command2_Click:
Exit Sub
Err_Command2_Click:
MsgBox Err.Description
Resume Exit_Command2_Click
End Sub
The query will be able to find the public function in the module.
I am considering the use of a tab control on a parent form for which I would like to have around 20 tabs. Each tab I am considering the use of one or two separate sub forms. Each sub form will have varied complexity in coded logic. By taking this approach will I severally reduce the performance of my application? I am currently using this in MS Access 2003. I will expect an average of 15 users at any given time on the various forms.
Thoughts?
Yes, performance will be degraded slightly for each subform. One or three isn't too bad but twenty is definitely going to cause you performance issues.
Once you have the subform working to your satisfaction either save the Record Source as a query and give it a name or save the query SQL string. Then either paste the query name or the query SQL string in the VBA code in the tab control change event.
Private Sub TabCtl_Change()
On Error GoTo TabCtl_Change_Error
Select Case Me.TabCtl.Value
Case Me.pagPartsConsumed.PageIndex
If Me.PartsConsumedsbf.Form.RecordSource <> "Equipment - Parts Consumed sbf" Then _
Me.PartsConsumedsbf.Form.RecordSource = "Equipment - Parts Consumed sbf"
....
Now just to ensure that I don't accidentally leave some subform recordsources filled in slowing down the app on startup I check to see if the file the code is running is an MDB (instead of an MDE. The function is below) then display a message telling me I have to remove the recordsource.
If Not tt_IsThisAnMDE Then
If Me.PartsConsumedsbf.Form.RecordSource <> "" Then _
MsgBox "Record source of Equipment - Parts Consumed sbf not empty"
...
End If
Public Function tt_IsThisAnMDE()
On Error GoTo tagError
Dim dbs As Database
Set dbs = CurrentDb
Dim strMDE As String
On Error Resume Next
strMDE = dbs.Properties("MDE")
If Err = 0 And strMDE = "T" Then
' This is an MDE database.
tt_IsThisAnMDE = True
Else
tt_IsThisAnMDE = False
End If
Exit Function
tagError:
Call LogError(Application.CurrentObjectName, "")
Exit Function
End Function
Also in the form unload event I clear the Recourd Source as well.
Private Sub Form_Unload(Cancel As Integer)
On Error GoTo Form_Unload_Error
Me.PartsConsumedsbf.Form.RecordSource = ""
....
BTW I almost always would put each subform on a seperate tab. Also that many tab entries gets visusally unwieldy. When I had a similar question my fellow Access MVPs suggested using a listbox along the left hand side to control which subform is viewable.
Also each combo box and list box will also slightly degrade the performance. So if you have those on a subform then consider similar logic.
In addition to adding recordsets at runtime, I would generally only use one or two tabs and a number of controls to load various subforms into a subform control.
The text for the On Click event of the control might be:
=WhichPage([Form],"lblLocations")
Where WhichPage is a function with the following lines, amongst others:
Function WhichPage(frm, Optional LabelName = "")
<..>
Select Case LabelName
Case "lblLocations"
frm("sfrmAll").SourceObject = "sfrmLocations"
<...>
If necessary, the link child and link master fields can be changed at runtime. The link master field is best set to the name of a control, rather than a field, to avoid errors.
Me.sfrmAll.LinkChildFields = "LocationKey"
Me.sfrmAll.LinkMasterFields = "txtLocationKey"
To expand on Remou's answer...here is a sub I wrote that dynamically loads a form into a subform control. You pass in the name of the form in the call and it will load it into the subform of the Main form. The arguments map to the arguments of Docmd.OpenForm method of Access. If the main form that is hosting the subform control is not open...it just does a regular open of the form. Otherwise it loads it into the subform control. If a where clause was passed in it is used to filter the subform.
Public Sub MyOpenForm(FormName As String, _
Optional View As AcFormView = acNormal, _
Optional FilterName As String = vbNullString, _
Optional WhereCondition As String = vbNullString, _
Optional DataMode As AcFormOpenDataMode, _
Optional WindowMode As AcWindowMode, _
Optional OpenArgs As String)
On Error GoTo PROC_ERR
Dim frm As Form
Dim strNewForm As String
Dim strCurrentForm As String
Dim strNewTable As String
Dim fDoNotFilter As Boolean
Dim strActionText As String
Dim strID As String
If Not IsLoaded("frmMain") Then
DoCmd.OpenForm FormName:=FormName, View:=View, FilterName:=FilterName, WhereCondition:=WhereCondition, DataMode:=DataMode, WindowMode:=WindowMode, OpenArgs:=OpenArgs
Else
strCurrentForm = Forms![frmMain]![sfrMyForm].SourceObject
If strCurrentForm <> FormName Then
Forms![frmMain]![sfrMyForm].SourceObject = vbNullString
Forms![frmMain]![sfrMyForm].SourceObject = FormName
End If
If WhereCondition <> vbNullString Then
Forms![frmMain]![sfrMyForm].Form.Filter = WhereCondition
Forms![frmMain]![sfrMyForm].Form.FilterOn = True
End If
End If
PROC_EXIT:
Exit Sub
PROC_ERR:
MsgBox Err.Description
Resume PROC_EXIT
End Sub