Access VBA: this application has requested the Runtime - ms-access

Running a VBA macro, sometimes it works well. But in some cases, I get the following error.
I have debugged the code but I don't get any error. The code is the following.
Public Sub Adjust_ComboBox()
On Error GoTo Adjust_ComboBox_Err
Dim mes As Form
Set mes = [Form_Treatment Details]
Dim count As Long
On Error Resume Next
For Each ctl In mes.Detail.Controls
If TypeName(ctl) = "ComboBox" Then
Dim comboitems() As Variant
count = 1
comboitems = ctl.Value
count = UBound(comboitems) + 1
ctl.Height = (300 * count)
Erase comboitems
End If
Next
Adjust_ComboBox_Exit:
Exit Sub
Adjust_ComboBox_Err:
MsgBox Error$
Resume Adjust_ComboBox_Exit
End Sub
How can it be possible to get this error?

This whole block of code looks odd to me.
Dim comboitems() As Variant
count = 1
comboitems = ctl.Value
count = UBound(comboitems) + 1
ctl.Height = (300 * count)
Erase comboitems
My questions are:
Why are you DIMing and ERASEing the combotems in a loop?
Why are you setting your array to the control's value?
Are you trying to set the height based on the number of items?
Why are you setting count=1 when it just gets overwritten two lines
later?
If I am guessing right on the answers to the questions I think you'd eliminate a few possible crashes by slimming down your loop code and using ListCount:
count = ctl.ListCount
if count > 0 then
ctl.Height = (300 * count)
else
ctl.Height = 300
end if

Related

MS Access - Object from another form isn't recognized

Our school project is to make a voting system in MS Access. So far this is what I've done:
Private Sub Command7_Click()
Dim President1 As Integer
Dim President2 As Integer
President1 = 0
President2 = 0
If Frame0.Value = 1 Then
DoCmd.Close
DoCmd.OpenForm "RESULTS"
President1 = President1 + 1
Me.lblpresresults1.Caption = President1
DoEvents
Else
DoCmd.Close
DoCmd.OpenForm "RESULTS"
President2 = President2 + 1
Me.lblpresresults2.Caption = President2
DoEvents
End If
End Sub
There are two forms, voting1 and RESULTS
There are two voting options in form voting1. When clicking a button beneath the two options, it should add +1 to a counter. And the resulting number should appear in a textbox in the form RESULTS.
But whenever i run it, it says "method or data member not found". Can someone help point out where the code went wrong? Is there something missing? Thanks in advance.
EDIT: The above code is the code in the aforementioned button
debugging.
try commenting out all the suspect lines using ' at the start of the line.
un-comment one at a time to find out which one is breaking your system.
You are closing the form before opening the next, thus pulling the feet under your code. Try:
Private Sub Command7_Click()
Dim President1 As Integer
Dim President2 As Integer
DoCmd.OpenForm "RESULTS"
If Frame0.Value = 1 Then
President1 = President1 + 1
Forms!RESULTS!lblpresresults1.Caption = President1
Else
President2 = President2 + 1
Forms!RESULTS!lblpresresults2.Caption = President2
End If
DoCmd.Close
End Sub
However, that will alway set the caption to "1", not adding anything. So perhaps:
Private Sub Command7_Click()
Dim President As Label
Dim Votes As Long
DoCmd.OpenForm "RESULTS"
If Frame0.Value = 1 Then
Set President = Forms!RESULTS!lblpresresults1
Else
Set President = Forms!RESULTS!lblpresresults2
End If
Votes = Val(President.Caption) + 1
President.Caption = CStr(Votes)
DoCmd.Close
End Sub
That won't save the votes anywhere, but that - I guess - is the next task.

DLookup 3075 Missing Operator Around NZ?

This is my code:
Private Sub Form_Current()
Set rs = CurrentDb.OpenRecordset("Sites", dbOpenDynaset, dbSeeChanges)
rs.Requery
rs.MoveFirst
If Nz(Me.Site_ID.Value) > 0 Then
Me.H2OBillingIDlbl.Caption = DLookup("H2OBillingIDNum", "Sites", "H2OBillingIDNum = " & Me.txtHotelID)
Else
Me.H2OBillingIDlbl.Caption = ""
End If
End Sub
The DLookup line is throwing the error.
Me.txtHotelID box is a text entry box on the form and is used to enter numbers only.
The H2OBillingIDNum field in the recordset is Long.
I have tried putting brackets around H2OBillingIDNum; .Value at the end of H2OBillingIDNum and Me.txtHotelID alternatively and combined; entering the data as a string in which case I get data mismatch error.
I don't believe I can use a SQL query because it is a text entry field, but if I'm wrong, I'll happily take the information as I've never heard of a SQL query like that and it's a faster and more accurate method of pulling the data.
I'm out of ideas. Any suggestions? Is it the NZ? Is there a better way of writing that? Should that not be included at all? If it helps, this is a DAO db.
The error must be that Me.txtHotelID is empty, therefore your DLookup call is incomplete
DLookup("foo", "bar", "myValue = ")
gives Runtime error 3075: Syntax error (missing operator) in 'myValue = '
Here is a guide on how to debug problems like this.
Take the code apart (one command per line), and use intermediate variables. Their values can be seen in break mode by hovering the mouse on the variable name, or in the Watch window.
Recommended reading: Debugging VBA Code
If you use DLookup, there is no need at all for a recordset, so I have removed it.
Run (or step through) this code, and the error will become clear:
Private Sub Form_Current()
Dim SiteID As Long
Dim HotelID As Long
Dim strCaption As String
SiteID = Nz(Me.Site_ID.Value, 0)
If SiteID > 0 Then
' Intentionally without Nz(), will throw error
HotelID = Me.txtHotelID
' Nz() will be needed here too!
strCaption = DLookup("H2OBillingIDNum", "Sites", "H2OBillingIDNum = " & HotelID)
Else
strCaption = ""
End If
Me.H2OBillingIDlbl.Caption = strCaption
End Sub
You can reduce it to:
Private Sub Form_Current()
Dim rs As DAO.Recordset
Dim SQL As String
Dim Caption As String
If Nz(Me!Site_ID.Value, 0) > 0 Then
SQL = "Select Top 1 H2OBillingIDNum From Sites Where H2OBillingIDNum = " & Nz(Me!txtHotelID.Value, 0) & ""
Set rs = CurrentDb.OpenRecordset("SQL", dbOpenDynaset, dbSeeChanges)
Caption = rs!Fields(0).Value
End If
Me!H2OBillingIDlbl.Caption = Caption
Set rs = Nothing
End Sub
As you can see, it doesn't make much sense, as you look up H2OBillingIDNum which you already have as Me!txtHotelID.Value, so it probably should read:
SQL = "Select Top 1 SomeTextField From Sites Where H2OBillingIDNum = ...
Sorry misunderstod you
I don't really see the purpose, but one thing is sure - if your Dlookup returns a Null you get ant error. You cannot load the caption with null.
An NZ around the Dlookup is needed. But i don't know if it is possible that the Dlookup doesn't find anything

Me.Recordset.AbsolutePosition can not move to current record in the form

i have a form with data sheet view i want to use this form as a list box (multi select extended), so when i click on each record/field in the form it uses (clear selection function) for unselected other records and just select record i have focused, now problem is when click on each field after running clear selection function it goes to the first record and did not moves cursor to current focused record.
it seems below code
Me.Recordset.AbsolutePosition = Pos1
does not work and will not be moved to current focused record.
the complete code is like below:
Private Sub P_Click()
On Error Resume Next
Dim ct As Control
Dim Cnt As Long, Rws As Long
Dim Pos1 As Long, Pos2 As Long
Pos1 = Me.Recordset.AbsolutePosition
Set ct = ActiveControl
' Clear other selections if Ctrl or Shift key
' is not simultaneously pressed.
If CtrlPressed = 0 And ShiftPressed = 0 Then
P_ClearSelections
Me.Recordset.AbsolutePosition = Pos1
Me.IsSelected = True
ct.SetFocus
GoTo ExitPoint
End If
If ShiftPressed > 0 Then
Rws = Me.SelHeight
If Rws > 1 Then
Pos2 = Me.SelTop - 1
For Cnt = Pos2 To Pos2 + Rws - 1
Me.Recordset.AbsolutePosition = Cnt
Me.IsSelected = True
Next
End If
GoTo ExitPoint
End If
Me.IsSelected = True
ExitPoint:
' Save the status
Me.Dirty = False
' Update display in SF_Selected
Me.Parent("SF_Selected").Requery
ActiveControl.SelLength = 0
Set ct = Nothing
On Error GoTo 0
End Sub
function clear selection is like below;
Public Sub P_ClearSelections()
On Error Resume Next
DoCmd.Echo False
' Clear all check boxes
CurrentDb.Execute "UPDATE tblItems " & _
"SET IsSelected = False;", dbFailOnError
Me.Requery
DoCmd.Echo True
On Error GoTo 0
End Sub
You are requerying the underlying recordset in your P_ClearSelections() procedure. From the Microsoft documentation:
There is also no assurance that a given record will have the same
AbsolutePosition if the Recordset object is requeried or reopened.
Bookmarks are still the recommended way of retaining and returning to
a given position and are the only way of positioning across all types
of Recordset objects.
MSDN AbsolutePosition
I suggest that you investigate the use of Bookmarks instead (and remove the On Error Resume Next statements).

Access subform, how to resize columns to best fit?

I have a form with a subform. This subform displays the results of a query that is created dynamically (user enters criteria, I build the SQL, then update the querydef and display). Problem is since the columns are dynamic the width of the columns isn't working out, some are cutting off text.
Is there a way to programmatically loop through the columns (or do the same without loop) and set them all to bestfit width after the query is refreshed?
EDIT: Here is what my code looks like now:
CurrentDb.QueryDefs("SearchResults").sql = sql
CurrentDb.QueryDefs.Refresh
Dim qdf1 As DAO.QueryDef
Dim fld1 As DAO.Field
Set qdf1 = CurrentDb.QueryDefs("SearchResults")
For i = 0 To qdf1.Fields.Count - 1
Set fld1 = qdf1.Fields(i)
fld1.CreateProperty "ColumnWidth", dbInteger
fld1.Properties("ColumnWidth") = -2 'Throws error
Set fld1 = Nothing
Next i
Me.Child20.SourceObject = "Query.SearchResults"
You can set column widths like so:
Sub SetColumnWidth()
Dim qdf1 As DAO.QueryDef
Dim fld1 As DAO.Field
Set qdf1 = CurrentDb.QueryDefs("query3")
For i = 0 To qdf1.Fields.Count - 1
Set fld1 = qdf1.Fields(i)
fld1.CreateProperty "ColumnWidth", dbInteger
'very narrow indeed
'fld1.Properties("ColumnWidth") = 200
'Or -2 : Sizes the column to fit the visible text
'but it is not quite as useful as it would seem
fld1.Properties("ColumnWidth") = -2
Set fld1 = Nothing
Next i
End Sub
See also http://support.microsoft.com/kb/210427
So I've run into this same problem just now. I was fortunate enough to have half of my queries work and the other half not. I've been using this code:
Sub QueryData(strSQL As String)
Dim qryData As DAO.QueryDef
Dim intcount As Integer
Set qryData = CurrentDb.QueryDefs("DataQuery")
qryData.SQL = strSQL
qryData.CreateProperty "ColumnWidth", dbInteger
qryData.Fields(0).Properties("ColumnWidth") = 5760
DoCmd.OpenQuery "DataQuery", , acReadOnly
End Sub
Which generated the error on half of the queries I tried to run with it. I traced it back to this odd, but simple truth: Columns built using an Alias (i.e. all formula columns and expressions) kick out this error. If the column is just a straight data pull, it works fine. If the column is, however, a formulated display.... it spits the no columwidth property error.
Hopefully this'll help someone out! I know this questions about a year old, but it was the first result Google found for me on the topic.
I was able to make this grab the open forms and autofit the selected subform within that form. If you have multiple forms/subforms you would just call the function with the new names using the lines of code at the end of the function and pasting them in your program.
Public Function AutoSizeSbCtrl(frmNameTar, sbCtrlNameTar)
For Each frm In Forms
frmName = frm.Name
If frmName = frmNameTar Then
For Each frmCtrl In frm.Controls
frmCtrlName = frmCtrl.Name
If frmCtrlName = sbCtrlNameTar Then
For Each sbfrmCtrl In frmCtrl.Controls
sbfrmCtrlName = sbfrmCtrl.Name
On Error Resume Next
sbfrmCtrl.ColumnWidth = -2
On Error GoTo 0
Next sbfrmCtrl
End If
Next frmCtrl
End If
Next frm
' paste the lines below in your code where you want it to trigger (i did on an update)
'frmNameTar= "frm12345" ' where frm12345 is the name of the form the subform is in
'sbCtrlNameTar="sbfrm67890" ' where sbfrm67890 is the name of the subform you are trying to autofit
'auSize = AutoSizeSbCtrl(frmNameTar, sbCtrlNameTar)
'end paste
End Function

Repetition of query to produce report

I am creating a bill of materials program.
There are two main tables named Products and Sub_Products.
In the Products table, the fields are (Product_Name, Code).
In the Sub_Products table, the fields are (Code, Sub_Name).
The tables are linked with code, i.e.: one product is made up of many sub_products, each sub_product is a product as well, making it have many sub_products.
I have created a query that reads a product and gets its sub_products. I need a query to compare Sub_Name with Product_Name and then check more sub_products,
continuing until no more sub_products are found.
Any ideas?
I guess you will have to use a script rather than SQL query to loop through them. Assuming that the products can be nested more than 3 levels.
I've been working on this exact problem in an ASP.NET MVC application. A function that gathered all the subproducts for each product and recursed on each subproduct worked well. We have some BOMs that are 15 levels deep.
I realize this question was asked a long time ago, but I had a very similar question and finally figured out a good answer. So I am posting it here in case anyone needs to know how to create a Bill of Materials.
In my example there is a table called "Part_Item_Table" which lists parent items and all of their childeren. Those childeren can also be parents to other childeren. The difficulty was that the BOM could be 3 levels deep all the way up to 30 levels deep or more. My "Part_Item_Table" also lists whether items are "Make" items or not. Only "Make" items will have childeren. The table you are querying may not have that feature, but the code below will probably still be helpful to get the idea.
This set of code uses several things that were new to me such as recursive code, calling a query I had already created and passing in a variable using the querydef methods, and using recordsets to get large information sets in and out of functions. I also used a sequence field in my BOM Table so I could sort by it and view the BOM in the order it is meant to be (Showing visually which level 3 items roll up into which level 2 items). If there is something that can be improved I am open to suggestions. This does work for my needs right now and hopefully it is helpful to someone else.
Option Compare Database
Public stFirstPart As String
Private Const BOMTable As String = "BOM_Table" 'Set this variable to the name of the table
Private Const ComponentQ As String = "GetComponentsQ" 'Set to the name of the query in the database
Function BOM()
Dim stQuery As String 'Used to make a query
Dim i As Integer 'Used to create the sequence number
Dim iLevel As Integer 'Used to show BOM level
Dim rsParent, rsBOMTable As DAO.Recordset 'Used to hold query results
'Make sure there is a part number in the form
If IsNull(Forms![Entry Form]![Part_Number]) Then
Debug.Print "There is no part number entered in the form"
MsgBox "There is no part number in the form.", vbOKOnly, "Can't fool me."
Exit Function
End If
stFirstPart = Forms![Entry Form]![Part_Number] 'Get the top part number from the form
'Make sure this is a Make item. Only make items will have childeren
stQuery = "SELECT ITEM.ITEM_NO, ITEM.MAKE_BUY_FLAG, ITEM.CURRENT_FLAG " & _
" FROM PART_ITEM_TABLE AS ITEM " & _
" WHERE (((ITEM.ITEM_NO)='" & stFirstPart & "') AND ((ITEM.MAKE_BUY_FLAG)='M') AND ((ITEM.CURRENT_FLAG)='Y'));"
Set rsParent = CurrentDb.OpenRecordset(stQuery)
If rsParent.EOF And rsParent.BOF Then
Debug.Print "This is not a make item"
MsgBox "This is not a Make item.", vbOKOnly, "I tried."
Exit Function
End If
'Clear the BOM table and load this first part number
DoCmd.SetWarnings False
DoCmd.RunSQL "Delete from " & BOMTable & ""
Set rsBOMTable = CurrentDb.OpenRecordset(BOMTable, dbOpenDynaset)
i = 1
iLevel = 1
rsParent.MoveFirst
With rsBOMTable
.AddNew
!Sequence = i
!Level = iLevel
!Item_Number = stFirstPart
!Make_Buy = "M"
.Update
End With
rsParent.Close
Set rsParent = Nothing
rsBOMTable.Close
Set rsBOMTable = Nothing
'-----------------------------------------------------------------------------------------------------------------------------------
'Start going down levels
'-----------------------------------------------------------------------------------------------------------------------------------
iLevel = 2
Call RecursiveLevels(stFirstPart, iLevel, i)
DoCmd.SetWarnings True
End Function
Function RecursiveLevels(PartNumber As String, iLevel As Integer, i As Integer)
Dim rsLevels As DAO.Recordset
Dim stPart As String
Set rsLevels = GetComponents(PartNumber)
If rsLevels.BOF And rsLevels.EOF Then
Debug.Print "This was a Make item with no children. That shouldn't happen. "; PartNumber
GoTo ExitPoint
End If
rsLevels.MoveFirst
Do While Not rsLevels.EOF
If rsLevels!Make_Buy <> "M" Then ' Anything that is not a Make item is written to the BOM table one line at a time.
i = i + 1
Call WriteToBOMTable(iLevel, i, rsLevels!Parent_Number, rsLevels!Component_Number, rsLevels!Make_Buy)
Else 'The Make item is written to the table, then we query for all of its children
stPart = rsLevels!Component_Number
i = i + 1
Call WriteToBOMTable(iLevel, i, rsLevels!Parent_Number, rsLevels!Component_Number, rsLevels!Make_Buy)
If stPart = stFirstPart Then 'Check to make sure this recursive thing doesn't go on forever.
Debug.Print "This part number is the same as the first part number. Circ Reference. "; stPart
GoTo ExitPoint
End If
iLevel = iLevel + 1 ' get ready to go one level deeper
Call RecursiveLevels(stPart, iLevel, i)
End If
rsLevels.MoveNext
Loop
ExitPoint:
iLevel = iLevel - 1 'Done with this level. Come back up a level.
rsLevels.Close
Set rsLevels = Nothing
End Function
Function WriteToBOMTable(Level As Integer, i As Integer, ParentNumber As String, ComponentNumber As String, MakeBuy As String)
Dim rsBOMTable As DAO.Recordset
Set rsBOMTable = CurrentDb.OpenRecordset(BOMTable, dbOpenDynaset)
With rsBOMTable
.AddNew
!Parent_Number = ParentNumber
!Item_Number = ComponentNumber
!Level = Level
!Make_Buy = MakeBuy
!Sequence = i
.Update
End With
Debug.Print "Level: "; Level; "Component: "; ComponentNumber
rsBOMTable.Close
Set rsBOMTable = Nothing
End Function
Function GetComponents(PartNumber As String) As DAO.Recordset
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs(ComponentQ)
qdf.Parameters("PartNumber") = PartNumber
Set GetComponents = qdf.OpenRecordset
End Function