Keeps jumping back to start of Sub as soon as it completes first iteration in the nested loop - excel

Very new to VBA coding. I inserted a Text Box (Active Control X) in my worksheet. Wrote a code to import data from MS Access database and save that data to an array. Later I am trying to print that array in the text box for user to see. but everytime my code enters the nested part of For loop, the running iteration of sub jumps back to the start of the code. Code than runs for multiple times make multiple SQL queries and excel crashes. I am not sure why code is jumping back to start of the sub?
Private Sub TextBox1_Change()
Dim sQuery As String
Dim ReturnData() As Variant
'Clear existing data in statuses area
Dim rngClearArea As Range
Dim wsFleetio As Worksheet
Set wsFleetio = ThisWorkbook.Worksheets("Test")
Dim Farm As String
Farm = wsFleetio.Range("B1").Value
'Set rngClearArea = FindTag(wsFleetio, "$Vehicle Status", 2, 0).Resize(1000, 4)
'rngClearArea.ClearContents
'Build query
sQuery = "SELECT [KillDate], [FarmName], [LoadType] FROM Loads WHERE ([FarmName] = '" & Farm & "' AND [KillDate] >= DateAdd('yyyy', -1, Date()))"
ReturnData = GetMerlinData(sQuery)
Dim leng As Integer
leng = UBound(ReturnData, 2)
Dim FarmData(500, 2) As Variant
Dim m As Integer
For m = 0 To UBound(ReturnData, 2)
FarmData(m, 0) = ReturnData(0, m)
FarmData(m, 1) = ReturnData(1, m)
FarmData(m, 2) = ReturnData(2, m)
Next
Dim i As Long, j As Long
For i = 0 To UBound(ReturnData, 2)
For j = 0 To 2
TextBox1.Text = TextBox1.Text & FarmData(i, j) & "---"
Next j
TextBox1.Text = TextBox1.Text & vbCrLf
Next i
End Sub
After running the first iteration of j, code jumps back to start of the code. I want it to run normally but not sure what the error is

Add a second TextBox, TextBox2 and use it in the loop: TextBox2.Text = TextBox2.Text & ...

Related

How do I force AfterUpdate Event for TextBoxes on a Modal Userform to run after programmaticaly changing their value

I have a programmatically designed Excel userform running modaly.
It sometimes crashes and when It does, I will have to start inputting data all over again.
I found a way of saving this volatile data on a worksheet from where I can recover them in case of crash so that I won't need to input them all over again. The problem is that when the TextBoxes are programmaticaly filled, the corresponding AfterUpdate Events do not run.
I have written codes to make them run but I get error that the macro does not exist. I even wrote separate non-Private Subroutines that should do the same thing the AfterUpdate does, but I still get the same error.
Here is the code that recovers data.
Private Sub Retrieve_Values()
Dim c, S_Row, E_Row, R_Count As Long, Tname, Vname As String
S_Row = 2
With TempWs
If Not IsEmpty(.Cells(S_Row, 1)) Then
If Not IsEmpty(.Cells(S_Row + 1, 1)) Then
R_Count = .Range(.Cells(S_Row, 1), .Cells(S_Row, 1).End(xlDown)).Rows.Count
Else
R_Count = 1
End If
E_Row = S_Row + R_Count - 1
For c = S_Row to E_Row
Tname = .Cells(c, 1).Value
Me.Controls(Tname) = .Cells(c, 2).Value
Vname = Tname
Tname = "Help_" & Tname
Run Tname Vname
Next
End If
End With
Below is a sample of code it should run
Sub Help_BIODATA_DATE_OVERRIDE_TextBox(ByVal Vname As String)
Dim MyValue As String
MyValue = Me.Controls(Vname).Value
If Not MyValue = "" Then
OV_Date = Extract_Date(MyValue)
Real_Date = OV_Date
Client_Dict("DATE OVERRIDE") = OV_Date
Else
Real_Date = DATE
Client_Dict("DATE OVERRIDE") = ""
End If
Me.Date_Label.Caption = Date_Display(Real_Date)
Age = Calculate_Age(Real_Date, D_O_B)
Me.Age_Label.Caption = Age
Day_Cash_Collections
Attendace_Register
Account_Summary
All codes are in the userform codemodule

Subscript out of range error in Excel VBA when I add a new worksheet at the end of the list of worksheets only when the VB window is closed

I have built an Excel Workbook that is intended for evaluation of an organization as a whole and then evaluation of each of several sites for that organization. There is an initial assessment and then an on-site assessment for the organization, and for each facility. Depending on the organization, the number of facilities will vary. There is a first "Configuration" tab where the user of the workbook enters (or copies and pastes) the list of facilities and determines which facilities are to be included in the evaluation.
The second and third worksheets are the assessment for the organization as a whole, and the fourth and fifth worksheets are template assessment forms for the facilities.
Once the list of facilities is entered, the user clicks on a button labeled "Create Facility Tabs" that steps through the facility list and creates the needed worksheets for each facility.
If the list is fresh (starting from its initial form), then the template worksheets are renamed for the first facility and new worksheets are created for the remainder.
If there are already worksheets identified, the software checks each facility to see if its page already exists, and only creates additional worksheets for newly added facilities.
When additional worksheets are needed, the code first counts the number of additional worksheets that are needed (two for each facility), creates those worksheets, and then steps through them copying the template contents onto the forms and the change code for the worksheets into the worksheet's module.
The software works perfectly over and over again when I have the VBA window open. It does everything it is supposed to do. However, when I close the VBA window, the code creates all the worksheets, copies everything into the first worksheet, and then raises a Subscript Out of Range error. Any ideas what I am doing wrong?
Here is the code:
Public Sub CreateFacilities()
Dim row As Long
Dim facility_name As String
Dim facility_list As String
Dim facilities As Variant
Dim include As Boolean
Dim ws_init As Worksheet
Dim ws_fac As Worksheet
Dim ws_new_init As Worksheet
Dim ws_new_fac As Worksheet
Dim ws_config As Worksheet
Dim facility_count As Long
Dim tabs_to_create As Long
Dim fac_initial_range As Range
Dim fac_initial_address As String
Dim fac_onsite_range As Range
Dim fac_onsite_address As String
Dim message As String
Dim title As String
Dim answer As Variant
Dim code_line As String
Dim b_width As Long
Dim c_width As Long
Dim counter As Long
Dim init_sheet_number As Long
Dim fac_sheet_number As Long
Dim tab_count As Long
title = "Creating Facility Tabs"
message = "Before you execute this function you should" & vbCrLf & "add any study-specific questions to the" & vbCrLf
message = message & "Initial Assessment - Facility1 and" & vbCrLf & "On-Site Assessment - Facility1 tabs so" & vbCrLf
message = message & "they will be included on the created facility tabs" & vbCrLf & vbCrLf
message = message & "Do you wish to continue?"
answer = MsgBox(message, vbYesNo + vbQuestion, title)
If answer = vbNo Then
Exit Sub
End If
Set ws_config = ThisWorkbook.Sheets("Configuration")
Set ws_init = ThisWorkbook.Sheets(4)
Set ws_fac = ThisWorkbook.Sheets(5)
b_width = ws_init.Columns("B").ColumnWidth
c_width = ws_init.Columns("C").ColumnWidth
Set fac_initial_range = ws_init.Range("A1:C" & Trim(Str(FindLastRow(ws_init))))
Set fac_onsite_range = ws_fac.Range("A1:C" & Trim(Str(FindLastRow(ws_fac))))
fac_initial_address = fac_initial_range.address
fac_onsite_address = fac_onsite_range.address
code_line = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule.Lines(1, 50) 'get code for each new worksheet
facility_list = "" 'get list of facilities
facility_count = 0
For row = 4 To 54
facility_name = ThisWorkbook.Sheets("Configuration").cells(row, 2).value
include = ThisWorkbook.Sheets("Configuration").cells(row, 4).value
If facility_name = "" Then 'reached the end of the list
Exit For
Else:
If include Then 'the Do Assessment column is marked TRUE
If Not WorksheetExists(facility_name) Then 'the tabs for this facility do not already exist
facility_list = facility_list & facility_name & ","
End If
End If
End If
Next row
facility_list = Left(facility_list, Len(facility_list) - 1) 'remove trailing comma
If facility_list = "" Then 'no new facilities were added to the list
MsgBox "There were no facilties specified for inclusion"
Exit Sub
End If
facilities = Split(facility_list, ",") 'there is a list of facilities to add
facility_count = UBound(facilities) + 1
If ActiveWorkbook.Sheets.Count = 5 Then 'no facility tabs have been added
If facility_count = 1 Then 'there is only one facility - no tabs need to be added
tabs_to_create = 0
facility_name = facilities(0)
ws_init.Name = CreateInitialTabName(facility_name)
ws_fac.Name = CreateOnSiteTabName(facility_name)
Else:
tabs_to_create = (facility_count - 1) * 2
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.Count), Count:=tabs_to_create
For counter = LBound(facilities) To UBound(facilities)
facility_name = facilities(counter)
If counter = 0 Then 'rename the first two facility worksheets that already exist
ws_init.Name = CreateInitialTabName(facility_name)
ws_fac.Name = CreateOnSiteTabName(facility_name)
Else: 'for the rest, add worksheets and copy template content and code
init_sheet_number = ((counter - 1) * 2) + 6
fac_sheet_number = init_sheet_number + 1
Set ws_new_init = ActiveWorkbook.Sheets(init_sheet_number) 'create initial assessment sheet for facility
ws_new_init.Columns("B").ColumnWidth = b_width
ws_new_init.Columns("C").ColumnWidth = c_width
ws_new_init.Name = CreateInitialTabName(facility_name)
fac_initial_range.Copy Destination:=ws_new_init.Range("A1")
ThisWorkbook.VBProject.VBComponents(ws_new_init.CodeName).CodeModule.AddFromString code_line
Set ws_new_fac = ActiveWorkbook.Sheets(fac_sheet_number) 'create on-site assessment sheet for facility
ws_new_fac.Columns("B").ColumnWidth = b_width
ws_new_fac.Columns("C").ColumnWidth = c_width
ws_new_fac.Name = CreateOnSiteTabName(facility_name)
fac_onsite_range.Copy Destination:=ws_new_fac.Range("A1")
ThisWorkbook.VBProject.VBComponents(ws_new_fac.CodeName).CodeModule.AddFromString code_line
End If
Next counter
End If
Else: 'there are more than 5 tabs in the workbook - some were already added
tab_count = ActiveWorkbook.Sheets.Count
tabs_to_create = facility_count * 2
ActiveWorkbook.Sheets.Add After:=ActiveWorkbook.Sheets(tab_count), Count:=tabs_to_create
For counter = LBound(facilities) To UBound(facilities)
facility_name = facilities(counter)
init_sheet_number = (counter * 2) + (tab_count + 1)
fac_sheet_number = init_sheet_number + 1
Set ws_new_init = ActiveWorkbook.Sheets(init_sheet_number)
Set ws_new_fac = ActiveWorkbook.Sheets(fac_sheet_number)
ws_new_init.Name = CreateInitialTabName(facility_name)
ws_new_fac.Name = CreateOnSiteTabName(facility_name)
ws_new_init.Columns("B").ColumnWidth = b_width
ws_new_fac.Columns("B").ColumnWidth = b_width
ws_new_init.Columns("C").ColumnWidth = c_width
ws_new_fac.Columns("C").ColumnWidth = c_width
fac_initial_range.Copy Destination:=ws_new_init.Range("A1")
fac_onsite_range.Copy Destination:=ws_new_fac.Range("A1")
ThisWorkbook.VBProject.VBComponents(ws_new_init.CodeName).CodeModule.AddFromString code_line
ThisWorkbook.VBProject.VBComponents(ws_new_fac.CodeName).CodeModule.AddFromString code_line
Next counter
End If
ws_config.Activate
MsgBox Str(facility_count) & " facilities added"
End Sub

Results of a vba function not refreshed

I am creating a spreadsheet for a client to manage his ALM. I developped it under Excel and VBA, request of my client.
One sheet "Data" calculates all the vba functions. If i calculate manually each cell all works fine, but if i run the macro it did not.
Do you have a solution? I can post the entire file if needed, for a better investigation.
At the beginning all the calculation where in excel cell, but i created dedicated function for each table, because the file was too big when saved.
Public Sub Main()
Dim i, nb_tableaux As Integer
Dim j, lignemax, BarWidth As Long
Dim ProgressPercentage As Double
Dim echeancier, nomtableau As String
Dim ws_data As Worksheet
Dim c As Range
Me.ProgressLabel.Caption = "Initialisation terminée. "
Set ws_data = Sheets("Data")
lignemax = ws_data.Range("DATA").Rows.Count
Application.ScreenUpdating = True
Application.EnableEvents = True
nb_tableaux = 17
For i = 1 To nb_tableaux
echeancier = tab_Tableaux(i, 0)
nomtableau = tab_Tableaux(i, 1)
Me.ProgressLabel.Caption = "En cours : " & echeancier
ws_data.Range(nomtableau).Calculate
'With Worksheets("Data")
For j = 1 To lignemax
For Each c In ws_data.Range(nomtableau).Rows(j)
formulaToCopy = c.Formula
c.ClearContents
c.Value = formulaToCopy
DoEvents
Next
Me.ProgressLabel.Caption = "En cours : " & echeancier & ", " & Format(j / lignemax, "0.0%") & " completed"
Me.Repaint
Next j
'End With
Me.Bar.Width = i * 200 / nb_tableaux
Me.Bar.Caption = Format(i / nb_tableaux, "0%") & " completed"
Next i
Application.ScreenUpdating = False
Application.EnableEvents = False
End Sub
after taking into account the recommandations you gave me for my previous answers, the code works better, but still not for some of the ranges.
My issue come from a wrong calculation of a argument in the fonction.
In fact, I use ligne=activecell.row - 8, to get the ligne of the range to calculate. But it works if i do it manually, as the actual cell is activated, but not when i call the function many times, as i can not activate each cell, it will be too long for the spreadsheet.
How can i get ligne calculated, with the correct address of the cell where the function is written?
I hope i am clear enough. Sorry for my English.
Public Function Taux_Mois(ByVal mMois As Range, ByVal sScenario As Range)
Dim ligne As Long
ligne = ActiveCell.row - 8
Select Case (Range("DATA[Flag]").Cells(ligne).Value = 0) Or (Range("DATA[frequence fixing]").Cells(ligne).Value = 0)
Case True
Taux_Mois = 0
Exit Function
Case False
Dim index_taux As Integer
Dim ajust As Long
index_taux = CInt(Range("DATA[Indexation ID]").Cells(ligne).Value)
If index_taux = 1 Then
ajust = 0
Else
Dim ajust1, dernierfixingt0, freqfixing As Integer
dernierfixingt0 = Range("DATA[Dernier fixing t0]").Cells(ligne).Value
freqfixing = Range("DATA[frequence fixing]").Cells(ligne).Value
ajust1 = (Int((mMois.Value - dernierfixingt0) / freqfixing) * freqfixing)
ajust = Worksheets("Market Data").Range("Taux_" & sScenario.Value).Offset(12 + dernierfixingt0 + ajust1, 1 + index_taux).Value
End If
Taux_Mois = Range("DATA[facteur taux (TVA, base)]").Cells(ligne).Value * (ajust + Range("DATA[Spread / Taux]").Cells(ligne).Value / 10000)
Exit Function
End Select
End Function

VBA - Object Required Error, Altering Object from Dictionary

I am programming a kind of parser which reads an Excel table and then creates a
List of processes with some properties like Name, StartTime, EndTime etc.
For this I have a class Process and in the main file, I have a processList (Scripting.Dictionary), where I put the processes as I read the lines... For this assignment, the key is a String called MSID.
Now the problem is that for some reason, I am only able to access the Object from the Dictionary and alter its parameters inside one part of my If-ElseIf statement. In the other case, it throws 424-object required error and I have no idea why.
Here is the code
Sub ParseMessages()
' ITERATOR VARIABLES
Dim wb As Workbook, ws As Worksheet
Dim rowIter As Long, row As Variant
Dim A As Variant, B As Variant, C As Variant, D As Variant, E As Variant, F As Variant ' A,B,C,D,E,F variables for the cells of each row
' PROCESS PARAMETERS
Dim MSID As Variant
Dim StartTime As Variant
Dim EndTime As Variant
' OBJECTS
Dim process As process
Dim processList As Scripting.Dictionary ' DICTIONARY where the error happens
Set processList = New Scripting.Dictionary
Worksheets(1).Activate
'####### MAIN LOOP ######################################################
For rowIter = 1 To 11
row = Rows(rowIter)
A = row(1, 1)
B = row(1, 2)
C = row(1, 3)
D = row(1, 4)
E = row(1, 5)
F = row(1, 6)
Dim startIndex As Long, endIndex As Long, count As Long
' ------ PROCESSSTART -> MSID, processName, startTime
If (.....) Then
Debug.Print (vbNewLine & "Process start")
If (...) Then ' --MSID
startIndex = InStr(F, "Nr") + 3 '3 to skip "Nr "
endIndex = InStr(startIndex, F, "(")
count = endIndex - startIndex
MSID = Mid(F, startIndex, count)
StartTime = B
Debug.Print (StartTime & " -> " & MSID)
' **** MAKE new Process object, add to collection
Set process = New process
process.StartTime = StartTime
process.MSID = MSID
processList.Add MSID, process ' Add to the dictionary, KEY, VALUE
ElseIf (...) Then ' --ProcessName
startIndex = InStr(F, "=") + 2
endIndex = InStr(F, "<") - 1
count = endIndex - startIndex
processName = Mid(F, startIndex, count)
Debug.Print (processName)
' **** Add Name to the last element of the dictionary
processList(processList.Keys(processList.count - 1)).Name = processName 'get last Process Object
processList(MSID).Name = "Just Testing" ' !!!! here it works
Else
End If
' ------ END OF PROCESS ->
ElseIf (......) Then
startIndex = InStr(D, "MSID") + 5
endIndex = InStr(startIndex, D, "]")
count = endIndex - startIndex
MSID = Mid(D, startIndex, count)
EndTime = B
Debug.Print (EndTime & " End of process " & MSID)
' **** Add End time for the process from the collection, specified by MSID
Debug.Print ("Test of " & processList(MSID).Name) ' !!!!! Doesn't work
processList(MSID).Name = "Just Prooooooving" ' !!!!! Here doesn't work
processList(MSID).EndTime = EndTime ' !!!!! Does not work
End If
Next
End Sub
So to specify the question - why is it that this works:
processList(MSID).Name = "Just Testing" ' !!!! here it works
And this doesn't:
processList(MSID).Name = "Just Prooooooving" ' !!!!! Here doesn't work
If I first prove if the Object with the MSID key exists in the dictionary,
it's not found.
If processList.Exists(MSID) Then
Debug.Print ("Process exists, altering it...")
processList(MSID).Name = "Just Prooooooving" ' !!!!! Here doesn't work
processList(MSID).EndTime = EndTime
End If
But on the very first line where the condition is evaluated, I get something different by debug. It's THERE! See picture below
Debugging - MSID there but not able to access Dictionary entry with this as a key
Can you suggest how to solve this issue?
Thank you very much in advance for your help!
So... It's a bit shameful but after some hours of trying to solve this problem I found out,
that I added the Object to the list with MSID="124 " as Key.
When I tried to access, I of course used MSID with value "124".
Notice the difference? Yes, that space at the end.
The tricky part is - VBA debugger trims spaces at the end of Strings,
so it's actually impossible to see it. The same situation is if you print this out - impossible to see...
So in the end, I spent many hours looking for the answer, which is so simple :/
All I can do is to laugh about this.

Retrieve only checkboxes that have been checked vba

Hello I have this loop that checks weather checkboxes have been checked or not, but the array that this loop creates stores every single checkbox value of the list of checkboxes regardless if it is checked or not. So, I am not sure how to create a second loop that will gather only the checkboxes that have been checked out of the array SelectedItemArray1(i). Thank you very much for your help in advance and this is what I have so far.
For i = 0 To Sheet1.ListBox1.ListCount - 1
If Sheet1.ListBox1.Selected(i) = True Then
SelectedItemArray1(i) = Sheet1.ListBox1.List(i)
End If
MsgBox SelectedItemArray1(i)
Next
Try this (untested) code and see how well it works for you:
Dim Msg As String
Dim i As Integer
If ListBox1.ListIndex = -1 Then
Msg = "Nothing"
Else
Msg = ""
For i = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(i) Then
Msg = Msg & ListBox1.List(i) & vbCrLf
End If
Next i
End If
If your list box allows multi-selection of check boxes, then it's a different kind of animal. I did some googling and found this article, which should hopefully give you some ideas. Also, take a look at this article, which seems more complete.
EDIT:
I thought it might help to give the multi-select code too, from the first article I linked:
Dim i As Long
Dim j As Long
Dim msg As String
Dim arrItems() As String
ReDim arrItems(0 To ListBox1.ColumnCount - 1)
For j = 0 To ListBox1.ListCount - 1
If ListBox1.Selected(j) Then
For i = 0 To ListBox1.ColumnCount - 1
arrItems(i) = ListBox1.Column(i, j)
Next i
msg = msg & Join(arrItems, ",") & vbCrLf & vbCrLf
End If
Next j
MsgBox msg

Resources