I'm using the following function to read files into a spreadsheet. I was thinking of adding a stop button (something like this) but the problem is that while this is running it completely locks up Excel and I cannot interact with it in any way. Is there a way to gracefully stop something like this? Note that these are huge files (500,000+ lines)
Function LoadFile(m)
Dim WrdArray() As String
Dim txtstrm As TextStream
Dim line As String
Dim clm As Long
Dim Rw As Long
Dim Dash As Worksheet
Set Dash = Sheets("Dashboard")
Set cellStatus = Dash.Range("E3")
Set txtstrm = FSO.OpenTextFile("s:\views_" & m & ".txt")
Rw = 1
Do Until txtstrm.AtEndOfStream
If Rw Mod 4 = 0 Then cellStatus.Value = "Loading " & m & "... /"
If Rw Mod 4 = 1 Then cellStatus.Value = "Loading " & m & "... |"
If Rw Mod 4 = 2 Then cellStatus.Value = "Loading " & m & "... \"
If Rw Mod 4 = 3 Then cellStatus.Value = "Loading " & m & "... -"
line = txtstrm.ReadLine
clm = 1
WrdArray() = Split(line, "|!|")
For Each wrd In WrdArray()
Sheets(m).Cells(Rw, clm) = wrd
clm = clm + 1
Next wrd
Rw = Rw + 1
Loop
txtstrm.Close
LoadFile = Rw
End Function
First, turn off screen refreshing and calculation.
Application.ScreenUpdating = False
Application.Calculation = xlManual
then at the very end, turn back on
Application.ScreenUpdating = True
Application.Calculation = XlCalculationAutomatic
Additonally, if you add some type of counter that, after X iterations, prompts the user to continue or not, something like
Dim myCount as Long
...your loop starts here
myCount = myCount + 1
If myCount mod 1000 = 0 then
toContinue = msgBox("Continue with macro?",vbYesNo)
If toContinue = vbNo then exit sub
End if
...continue loop
Edit: Bah, I'll have to tweak that If myCount mod 1000 = 0 to something better...basically an even divisor of 1000 or something.
Also, is the loading "animation" required? I bet that contributes to it taking long when running over that many cells. And, just thought of it, when you turn off screenupdating, you won't see that animation, so maybe comment it out and see how it runs.
In order for excel not to 'lock up' you have to call 'DoEvents'. Using the following will also speed up your process, however it appears as though you'll need screen updating to update the status bar, and EnableEvents to operate your button press event.
Application.ScreenUpdating = False
Application.Calculation = xlManual
Application.EnableEvents = False
You can use the application's status bar at the very bottom if you want by doing the following:
Application.StatusBar = "Your Value Here"
Just make sure to clear it before you leave your function. If you wanted to be really 'safe' you can store its old previous value before writing to it then restore it here.
Application.StatusBar = ""
Your modified code is below:
Function LoadFile(m)
Dim WrdArray() As String
Dim txtstrm As TextStream
Dim line As String
Dim clm As Long
Dim Rw As Long
Dim Dash As Worksheet
Application.Calculation = xlManual
Set Dash = Sheets("Dashboard")
Set cellStatus = Dash.Range("E3")
Set txtstrm = FSO.OpenTextFile("s:\views_" & m & ".txt")
Rw = 1
Do Until txtstrm.AtEndOfStream
If Rw Mod 4 = 0 Then Application.StatusBar = "Loading " & m & "... /"
If Rw Mod 4 = 1 Then Application.StatusBar = "Loading " & m & "... |"
If Rw Mod 4 = 2 Then Application.StatusBar = "Loading " & m & "... \"
If Rw Mod 4 = 3 Then Application.StatusBar = "Loading " & m & "... -"
line = txtstrm.ReadLine
clm = 1
WrdArray() = Split(line, "|!|")
For Each wrd In WrdArray()
Sheets(m).Cells(Rw, clm) = wrd
clm = clm + 1
Next wrd
Rw = Rw + 1
'This will insure that excel doesn't lock up or freeze
DoEvents
Loop
txtstrm.Close
LoadFile = Rw
Application.Calculation = XlCalculationAutomatic
Application.StatusBar = ""
End Function
Not sure why you do this in a Function, but if you have Sub that calls this, it may be better to pause calculation there.
Anyway, try this (dumping array values in one go):
Function LoadFile(m)
Dim WrdArray() As String
Dim txtstrm As Object
Dim line As String
Dim clm As Long ' Now used as number of items in the Split
Dim CalcMode As Long
Dim Rw As Long
Dim Dash As Worksheet
Set Dash = Sheets("Dashboard")
'Set cellStatus = Dash.Range("E3")
Set txtstrm = FSO.OpenTextFile("s:\views_" & m & ".txt")
Rw = 1
CalcMode = Application.Calculation ' Save calculation mode
Application.Calculation = xlCalculationManual ' Change to Manual Calculation
Do Until txtstrm.AtEndOfStream
Application.StatusBar = Now & ": Loading " & m & " (Rw: " & Rw & ")"
'If Rw Mod 4 = 0 Then cellStatus.Value = "Loading " & m & "... /"
'If Rw Mod 4 = 1 Then cellStatus.Value = "Loading " & m & "... |"
'If Rw Mod 4 = 2 Then cellStatus.Value = "Loading " & m & "... \"
'If Rw Mod 4 = 3 Then cellStatus.Value = "Loading " & m & "... -"
line = txtstrm.ReadLine
'clm = 1
WrdArray = Split(line, "|!|")
clm = UBound(WrdArray) + 1 ' Number of items in the split
' Dump the array to cells value to resized range from Col A
Sheets(m).Cells(Rw, "A").Resize(, clm).Value = WrdArray
'For Each wrd In WrdArray()
' Sheets(m).Cells(Rw, clm) = wrd
' clm = clm + 1
'Next wrd
Rw = Rw + 1
Loop
txtstrm.Close
Application.StatusBar = False ' Reset status bar
Application.Calculation = CalcMode ' restore calculation mode
LoadFile = Rw
End Function
Related
My programm looks for a list of data from Sheets1 into sheets2 or Sheets3 depends on request in sheets1
the programm run properly when the source of research has a range with 2 columns
but with more then 2 columns at the program run only one time at the second time error 13 appears.
please find attached the programm.
thanks for your help
Tarik
Sub Plan_med()
Application.ScreenUpdating = False
Dim i As Long
Dim j As Long
Dim ColumnA As Range
Dim ColumnB As Range
Dim ColumnC As Range
Dim F2 As Range
Dim DernligneA As Long
Dim DernligneB As Long
Dim DernligneC As Long
Dim DernlistA As Long
Dim DernlistB As Long
Dim DernlistC As Long
Dim Dernlist As Long
Dim Dernligne As Long
Dim Medecin As String
Dim Caserne As String
Dim INTERV As String
Dim N As Long
Sheets("Feuil1").Range("L1:Z150").Clear
N = Sheets("Feuil1").Range("D5")
Medecin = Sheets("Feuil1").Range("E5")
Caserne = Sheets("Feuil1").Range("C5")
INTERV = Sheets("Feuil1").Range("B5")
Sheets("Feuil1").Range("D5").Value = N 'inutile car redondant
If Sheets("feuil1").Range("B5") = "ITJ" Then
Fichier = "INT JOUR"
Else: Fichier = "INT NUIT"
End If
DernlistA = Sheets(Fichier).Range("A" & Rows.Count).End(xlUp).Row
DernlistB = Sheets(Fichier).Range("E" & Rows.Count).End(xlUp).Row
DernlistC = Sheets(Fichier).Range("I" & Rows.Count).End(xlUp).Row
DernligneA = Sheets(Fichier).Range("C3").End(xlDown).Rows + 1
DernligneB = Sheets(Fichier).Range("G3").End(xlDown).Rows + 1
DernligneC = Sheets(Fichier).Range("K3").End(xlDown).Rows + 1
If Sheets("feuil1").Range("C5") = "CASERNE 1" Then
Dernlist = DernlistA
Set ColumnA = Sheets(Fichier).Range("A2:C" & DernligneA)
Set F2 = Sheets(Fichier).Range("A1:A" & DernlistA)
Dernligne = DernligneA
End If
If Sheets("feuil1").Range("C5") = "CASERNE 2" Then
Dernlist = DernlistB
Set ColumnA = Sheets(Fichier).Range("E2:G" & DernligneB)
Set F2 = Sheets(Fichier).Range("E1:E" & DernlistB)
Dernligne = DernligneB
End If
If Sheets("feuil1").Range("C5") = "CASERNE 3" Then
Dernlist = DernlistC
Set ColumnA = Sheets(Fichier).Range("I2:K" & DernligneC)
Set F2 = Sheets(Fichier).Range("I1:I" & DernlistC)
Dernligne = DernligneC
End If
j = 1
For i = 2 To Dernligne
If Not IsEmpty(ColumnA.Range("A" & i)) And IsEmpty(ColumnA.Range("C" & i)) Then
ColumnA.Range("A" & i).Copy Sheets("Feuil1").Range("M" & j)
j = j + 1
End If
Next i
Sheets("Feuil1").Range("M1:M" & N).Copy Sheets("Feuil1").Range("K1")
j = 1
For i = 1 To Dernlist
If F2.Range("A" & i) = Sheets("Feuil1").Range("K" & j) Then
F2.Range("C" & i) = "Intervention en cours" & " " & Medecin & " " & Date
j = j + 1
End If
Next i
Application.ScreenUpdating = True
End Sub
I want to write some VBA code that will count how many sets of "contiguous rows of Ts" there are in a single column in a worksheet. However I want such data sets to only be counted if there are more than 500 rows after the final T in a set that contain F values. For example, if T values are found at rows 500-510, then rows 511- 1010 would have to contain F values for one to be added to the count. If another T is encountered before reaching 1010, then the code would "reset" the 500 row counter and begin again.
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1600 = F
row 1601 - 1611 = T
row 1612 - 3000 = F
In this case the counter would display 2
Conversely:
row 1 - 1000 = F
row 1001 - 1011 = T
row 1012 - 1400 = F
row 1401 - 1411 = T
row 1412 - 3000 = F
The counter would only display 1 as the Ts in cluster 1001-1011 are <500 rows within cluster 1401-1411.
I am also aware that in some scenarios there may be a set of Ts that are within 500 rows of the end of overall data. These would also need to be ignored from the count (I.e. using the example above, if Ts occurred a 2,700 - 2710, in a set of data with 3,000 rows, these would need to be ignored from the count). Similarly I would need to exclude rows 1-500 from the count also.
I don't know if this would be possible or even how to begin writing the code for this, so any assistance will be greatly appreciated. Excerpt of data:
F
F
F
F
F
F
F
F
F
T
T
T
T
T
F
F
F
F
F
F
F
F
This is going to be added to a much larger macro which then goes to filter out all rows containing Ts and deleting them. However I want to perform the count of contiguous Ts first before taking this step.
Code for rest of macro (This code is called by another macro which takes the values generated and pastes them into a master file):
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim Rng As Range, Cell As Range
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("A3:Q3").Copy
.Range("A3:Q3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:Q3").Copy
End With
End Sub
Code with Tim's suggested additions:
Sub Populate_Ensocoat()
On Error GoTo eh
Dim MyBook As String
Dim Wb As Workbook
Dim strFolder As String
Dim strFil As String
Dim StartTime As Double
Dim SecondsElapsed As Double
Dim xCount As Long
Dim SourceRang1 As Range
Dim FillRange1 As Range
'Code to improve performance
Application.ScreenUpdating = False
Application.EnableEvents = False
'Code to Prompt user to select file location
With Application.FileDialog(msoFileDialogFolderPicker)
.AllowMultiSelect = False
.Show
strFolder = .SelectedItems(1)
Err.Clear
End With
'Code to count how many files are in folder and ask user if they wish to continue based on value counted
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> ""
xCount = xCount + 1
strFil = Dir()
Loop
If MsgBox("You have selected " & xCount & " files. Are you sure you wish to continue?", vbYesNo) = vbNo Then GoTo eh
'Code to Start timer
StartTime = Timer
'Code to make final report sheet visible and launch sheet hidden
Sheet1.Visible = True
Sheet1.Activate
Sheets("Sheet3").Visible = False
'declaring existing open workbook's name
MyBook = ActiveWorkbook.Name
'Code to cycle through all files in folder and paste values into master report
strFil = Dir(strFolder & "\*.csv*")
Do While strFil <> vbNullString
Set Wb = Workbooks.Open(strFolder & "\" & strFil)
Call RollMap_Ensocoat(Wb)
Workbooks(MyBook).Activate
ActiveSheet.Paste
Selection.HorizontalAlignment = xlCenter
ActiveCell.Offset(1).Select
Wb.Close SaveChanges:=False
strFil = Dir
Loop
'Formatting of values in final report
Range("B:I").NumberFormat = "#,##0"
Range("J:K").NumberFormat = "0.000"
Range("L:L").NumberFormat = "0.00"
Range("P:P").NumberFormat = "dd/MM/yyyy"
Range("Q:Q").NumberFormat = "hh:mm"
'Code to add header data to report (i.e. total files, name of person who created report, date and time report was created)
Range("Y2").Value = Now
Range("H2").Value = "# of Files Reported on: " & xCount
Range("P2").Value = Application.UserName
'Re-enabling features disabled for improved macro performance that are now needed to display finished report
Application.EnableEvents = True
Application.ScreenUpdating = True
'Code to refresh sheet so that graphs display properly
ThisWorkbook.RefreshAll
'Code to automatically save report in folder where files are located. Overrides warning prompting user that file is being saved in Non-macro enabled workbook.
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:=strFolder & "\" & "Summary Report", FileFormat:=xlOpenXMLWorkbook
Application.DisplayAlerts = True
'Code to display message box letting user know the number of files reported on and the time taken.
SecondsElapsed = Round(Timer - StartTime, 2)
MsgBox "Operation successfully performed on " & xCount & " files in " & SecondsElapsed & " seconds." & vbNewLine & vbNewLine & "Report created at location: " & Application.ActiveWorkbook.FullName, vbInformation
Done:
Exit Sub
eh:
MsgBox "No Folder Selected. Please select re-select a board grade"
End Sub
Sub RollMap_Ensocoat(Wb As Workbook)
Dim ws As Worksheet
Dim finalRow As Long
'Set name of first sheet in spreadsheet to "1"
With Wb.Sheets(1)
.Name = "1"
.Range("H1").Formula = "=TCount(G3:G10000)"
End With
'Code to delete all rows that contain a "T" in column G" (Indicating a tab was fired and thus is waste)
With Sheets("1")
finalRow = .Range("G" & Rows.Count).End(xlUp).Row
.AutoFilterMode = False
With .Range("G4:G" & finalRow)
.AutoFilter Field:=1, Criteria1:="T"
.Offset(1, 0).SpecialCells(xlCellTypeVisible).EntireRow.Delete
End With
.AutoFilterMode = False
'Code to calculate all the important values of each reel that will be pasted into the master report.
End With
Set ws = Wb.Sheets.Add(After:=Sheets(Wb.Sheets.Count))
With ws
.Range("A3").FormulaR1C1 = "=MAX('1'!C)"
.Range("B3").Formula = "=A3*I3"
.Range("C3").Formula = "=SUBTOTAL(109,'1'!B4:B10000)"
.Range("D3").Formula = "=SUBTOTAL(109,'1'!C4:C10000)"
.Range("E3").Formula = "=SUBTOTAL(109,'1'!D4:D10000)"
.Range("F3").Formula = "=SUBTOTAL(109,'1'!E4:E10000)"
.Range("G3").Formula = "=SUBTOTAL(109,'1'!F4:F10000)"
.Range("H3").Formula = "=SUM(C3:G3)"
.Range("I3").Formula = "='1'!A1"
.Range("J3").Formula = "=H3/(A3*I3)"
.Range("K3").Value = "0.21"
.Range("L3").Value = Wb.Name
.Range("M3").Formula = "=Left(L3, Len(L3) - 4)"
.Range("M3").Copy
.Range("M3").PasteSpecial xlPasteValues
.Range("N3").Formula = "=RIGHT(M3, 11)"
.Range("O3").Formula = "=LEFT(N3,2) & ""/"" & MID(N3,3,2) & ""/20"" & MID(N3,5,2)"
.Range("P3").Formula = "=MID(N3,8,2)& "":"" & MID(N3,10,2)"
.Range("Q3").Formula = "=Left(L3, Len(L3) - 16)"
.Range("R3").Formula = "='1'!H1"
.Range("A3:R3").Copy
.Range("A3:R3").PasteSpecial xlPasteValues
Application.CutCopyMode = False
.Range("A3:R3").Copy
End With
End Sub
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv
End Function
Something like this.
You may need to adjust if I made wrong assumptions about your rules.
Function TCount(rng As Range)
Const GAP_SIZE As Long = 5 '<< low number for testing...
Dim rv As Long, i As Long, fCount As Long, n As Long, d
Dim haveT As Boolean, earlyT as Boolean
rv = 0
d = rng.Value
n = UBound(d, 1)
fCount = 0
If n > GAP_SIZE Then
For i = 1 To n
If d(i, 1) = "T" Then
fCount = 0
If i <= GAP_SIZE Then earlyT = True '<<EDIT
haveT = True
Else
fCount = fCount + 1
If fCount = GAP_SIZE And haveT Then
rv = rv + 1
haveT = False
End If
End If
Next i
End If
TCount = rv - IIf(earlyT, 1, 0) '<< EDIT
End Function
I've implemented this macro whereby if i run it, it will show me the column and row of the word "needle" in the range A1:Z20. Although if there are multiple words of "needle" it will only output the last. How can I change this code to show me the first occurrence of the word?
Hope this makes sense, and here is my code so far:
Sub NeedleSearch()
Dim SearchSpace As Variant
Dim found As Boolean
found = False
SearchSpace = Range("A1:z20").Value
Dim i As Integer, j As Integer
For i = 1 To 20
For j = 1 To 26
If SearchSpace(i, j) = "needle" Then
Range("A25").Value = "Column " & j
Range("B25").Value = "Row " & i
found = True
End If
Next j
Next i
If found = False Then
Range("A25").Value = "needle not found"
Range("B25").Value = " "
End If
End Sub
With No Repeated Words
With 1 Repeated Word
If you need only first occurense just quit your loops!
Sub NeedleSearch()
Dim SearchSpace As Variant
Dim found As Boolean
found = False
SearchSpace = Range("A1:z20").Value
Dim i As Integer, j As Integer
For i = 1 To 20
For j = 1 To 26
If SearchSpace(i, j) = "needle" Then
Range("A25").Value = "Column " & j
Range("B25").Value = "Row " & i
found = True
End If
If found Then _
Exit For
Next j
If found Then _
Exit For
Next i
If found = False Then
Range("A25").Value = "needle not found"
Range("B25").Value = " "
End If
End Sub
To elaborate further: What this code actually does, if there are multiple instances of needle is, it will print all instances of found cells into A25:B25. Let's say there are 3 instances of needle e.g. in A1, B2 and C3. Your loop prints A1 into A25:B25 first, then B2 and then C3. Because it is happening so fast, you only see C3 or what you called the "last occurence".
What you can do to print out all solutions (which is what I'm guessing you're trying to do in the end) you could change your code to something like this:
Sub NeedleSearch()
Dim SearchSpace As Variant
Dim found As Boolean
found = False
SearchSpace = Range("A1:z20").Value
Dim ws As Worksheet
Dim i As Integer
Dim j As Integer
Dim k As Integer
Set ws = ThisWorkbook.Sheets(1)
k = 25
For i = 1 To 20
For j = 1 To 26
If SearchSpace(i, j) = "needle" Then
ws.Cells(k, 1).Value = "Occurence " & k - 24
ws.Cells(k, 2).Value = "Column " & j
ws.Cells(k, 3).Value = "Row " & i
k = k + 1
found = True
End If
Next j
Next i
If found = False Then
ws.Range("A25").Value = "needle not found"
End If
End Sub
Change your Sheet ID accordingly.
HTH
you can avoid loops by means of Find() method of Range object:
Option Explicit
Sub NeedleSearch()
Dim f As Range
Set f = Range("A1:Z20").Find(what:="needle", LookIn:=xlValues, lookat:=xlWhole, After:=Range("Z20"), SearchOrder:=xlByRows)
If f Is Nothing Then
Range("A25").Value = "needle not found"
Range("B25").Value = " "
Else
Range("A25").Value = "Column " & f.Column
Range("B25").Value = "Row " & f.Row
End If
End Sub
that can also be rewritten as follows:
Sub NeedleSearch()
Dim f As Range
Dim arr As Variant
Set f = Range("A1:Z20").Find(what:="needle", LookIn:=xlValues, lookat:=xlWhole, After:=Range("Z20"), SearchOrder:=xlByRows)
If f Is Nothing Then
arr = Array("needle not found", " ")
Else
arr = Array("Column " & f.Column, "Row " & f.Row)
End If
Range("A25:B25").Value = arr
End Sub
I currently have a macro which goes through a column on my master spreadsheet, then exports all the rows where the value input at the start matches the value in the column. It then saves the new worksheet as the value. Here is the code I currently have:
Option Explicit
Public Const l_HeaderRow As Long = 2 'The header row of the data sheet
Public Const l_DistanceCol As Long = 5 'The column containing the distance values
Public Sub ExportDistance()
Dim ws_Data As Worksheet, wb_Export As Workbook, ws_Export As Worksheet
Dim l_InputRow As Long, l_OutputRow As Long
Dim l_LastCol As Long
Dim l_NumberOfMatches As Long
Dim s_Distance As String, l_Distance As Long
Dim s_ExportPath As String, s_ExportFile As String, s_PathDelimiter As String
Set ws_Data = ActiveSheet
s_Distance = InputBox("Enter Distance to Export to New File", "Enter Distance")
If s_Distance = "" Then Exit Sub
l_Distance = CLng(s_Distance)
l_NumberOfMatches = WorksheetFunction.Match(l_Distance, ws_Data.Columns(5), 0)
If l_NumberOfMatches <= 0 Then Exit Sub
'Application.ScreenUpdating = False
'Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
On Error Resume Next
Call Application.Workbooks.Add
Set wb_Export = Application.Workbooks(Application.Workbooks.Count)
Set ws_Export = wb_Export.Worksheets(1)
Call wb_Export.Worksheets("Sheet2").Delete
Call wb_Export.Worksheets("Sheet3").Delete
Application.DisplayAlerts = True
ws_Export.Name = GetNextSheetname(ws_Data.Name & "-" & s_Distance, wb_Export)
Call ws_Data.Rows(1).Resize(l_HeaderRow).Copy
Call ws_Export.Rows(1).Resize(l_HeaderRow).Select
Call ws_Export.Paste
l_OutputRow = l_HeaderRow + 1
l_LastCol = ws_Data.UsedRange.Columns.Count
For l_InputRow = l_HeaderRow + 1 To ws_Data.UsedRange.Rows.Count
If ws_Data.Cells(l_InputRow, l_DistanceCol).Value = l_Distance Then
Call ws_Data.Range(ws_Data.Cells(l_InputRow, 1), ws_Data.Cells(l_InputRow, l_LastCol)).Copy
Call ws_Export.Rows(l_OutputRow).Select
Call ws_Export.Paste
l_OutputRow = l_OutputRow + 1
ElseIf ws_Data.Cells(l_InputRow, l_DistanceCol).Value = l_Distance Then
Call ws_Data.Range(ws_Data.Cells(l_InputRow, 1), ws_Data.Cells(l_InputRow, l_LastCol)).Copy
Call ws_Export.Rows(l_OutputRow).Select
Call ws_Export.Paste
l_OutputRow = l_OutputRow + 1
End If
Next l_InputRow
s_ExportPath = ThisWorkbook.Path
s_PathDelimiter = Application.PathSeparator
If Right(s_ExportPath, 1) <> s_PathDelimiter Then s_ExportPath = s_ExportPath & s_PathDelimiter
s_ExportPath = s_ExportPath & "Output" & s_PathDelimiter
If Dir(s_ExportPath) = Empty Then
Call MkDir(s_ExportPath)
End If
Select Case Application.DefaultSaveFormat
Case xlOpenXMLWorkbook
s_ExportFile = s_Distance & ".xlsx"
Case xlOpenXMLWorkbookMacroEnabled
s_ExportFile = s_Distance & ".xlsm"
Case xlExcel12
s_ExportFile = s_Distance & ".xlsb"
Case xlExcel8
s_ExportFile = s_Distance & ".xls"
Case xlCSV
s_ExportFile = s_Distance & ".csv"
Case Else
s_ExportFile = s_Distance
End Select
Call wb_Export.SaveAs(Filename:=s_ExportPath & s_ExportFile, FileFormat:=Application.DefaultSaveFormat)
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Public Function GetNextSheetname(s_Name As String, Optional wb_Book As Workbook) As String
Dim l_FIndex As Long
Dim s_Target As String
If wb_Book Is Nothing Then Set wb_Book = ActiveWorkbook
s_Name = Left(s_Name, 31)
If IsValidSheet(wb_Book, s_Name) Then
l_FIndex = 1
s_Target = Left(s_Name, 27) & " (" & l_FIndex & ")"
Do While IsValidSheet(wb_Book, s_Target)
l_FIndex = l_FIndex + 1
If l_FIndex < 10 Then
s_Target = Left(s_Name, 27) & " (" & l_FIndex & ")"
ElseIf l_FIndex < 100 Then
s_Target = Left(s_Name, 26) & " (" & l_FIndex & ")"
ElseIf l_FIndex < 1000 Then
s_Target = Left(s_Name, 25) & " (" & l_FIndex & ")"
End If
Loop
GetNextSheetname = s_Target
Else
GetNextSheetname = s_Name
End If
End Function
Public Function IsValidSheet(wbSearchBook As Workbook, v_TestIndex As Variant) As Boolean
Dim v_Index As Variant
On Error GoTo ExitLine
v_Index = wbSearchBook.Worksheets(v_TestIndex).Name
IsValidSheet = True
Exit Function
ExitLine:
IsValidSheet = False
End Function
Please will you help me make this loop through a list of values, rather than my having manually to run the macro each time and input the value myself?
Download this example here.
This is a simple example of how to loop through one range and loop through another range to find the values.
It loops through Column D and then loops through column A, when it finds a match it does something, so basically Column D has taken the place of your inputbox.
run the macro
The code
Sub DblLoop()
Dim aLp As Range 'column A
Dim dLp As Range, dRw As Long 'column D
Dim d As Range, a As Range
Set aLp = Columns("A:A").SpecialCells(xlCellTypeConstants, 23)
dRw = Cells(Rows.Count, "D").End(xlUp).Row
Set dLp = Range("D2:D" & dRw)
'start the loop
'loops through column D and finds value
'in column A, and does something with it
For Each d In dLp.Cells 'loops through column D
For Each a In aLp.Cells 'loops through column A
If d = a Then
'When a match, then do something
'this is where your actual code would go
Range("A" & a.Row & ":B" & a.Row).Copy Cells(Rows.Count, "F").End(xlUp).Offset(1)
End If
Next a 'keeps going through column A
Next d 'next item in column D
End Sub
I have the below sub that checks on a separate worksheet if the created number in textbox8 already exists, at the moment there is a message box that alerts the user that the part number already exists, they have to click OK, then the number is incremented by 1, the process is repeated until a unique number is found. This is the written to the worksheet along with some other data.
What I need to do is remove the message box so it will automatically search and find the next available number.
I added the following code to the sub, but this has no effect:
Application.DisplayAlerts = False
MsgBox "This already exists"
SendKeys "{ENTER}"
Application.DisplayAlerts = True
code
'Create part number and check
Private Sub CommandButton2_Click()
With TextBox26
If myreset = True Then
.Tag = 0
myreset = False
End If
.Tag = Val(.Tag) + 1
.Text = "-" & VBA.Format(Val(.Tag), "0000")
End With
Dim iNum(1 To 8) As String
iNum(1) = TextBox24.Value
iNum(2) = TextBox25.Value
iNum(3) = TextBox26.Value
TextBox8.Value = iNum(1) + iNum(2) + iNum(3)
'check article exists
Dim emptyRow As Long
Dim rcnt As Long
Dim i As Long
ActiveWorkbook.Sheets("existing").Activate
rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To rcnt
If TextBox8.Text = Sheets("existing").Range("A" & i).Value Then
Application.DisplayAlerts = False
MsgBox "This already exists"
SendKeys "{ENTER}"
Application.DisplayAlerts = True
Exit Sub
End If
Next
Range("A1").Select
Do
If IsEmpty(ActiveCell) = False Then
ActiveCell.Offset(1, 0).Select
End If
Loop Until IsEmpty(ActiveCell) = True
ActiveCell.Value = TextBox8.Text
To remove the message Box all you need to do is delete the following lines in your code
Application.DisplayAlerts = False
MsgBox "This already exists"
SendKeys "{ENTER}"
Application.DisplayAlerts = True
I am not sure what the first part of the code is doing. if you could provide some example I can help with that. But I have rationalized the second part and this will now achieve what the original code was attempting to achieve with lesser lines.
'check article exists
Dim emptyRow As Long
Dim rcnt As Long
Dim i As Long
Dim varProdCode As Long
ActiveWorkbook.Sheets("existing").Activate
varProdCode = TextBox8.Text
rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row
Do Until varProdCode = 0
For i = 2 To rcnt
If varProdCode = Sheets("existing").Range("A" & i).Value Then
varProdCode = varProdCode + 1
Exit For
Else
Range("A" & Rows.Count).End(xlUp).Offset(1, 0).Value = varProdCode
varProdCode = 0
Exit Sub
End If
Next
Loop
This is the code that works
Private Sub CommandButton2_Click()
With TextBox26
If myreset = True Then
.Tag = 0
myreset = False
End If
.Tag = Val(.Tag) + 1
.Value = VBA.Format(Val(.Tag), "0000")
End With
Dim emptyRow As Long
Dim rcnt As Long
Dim c As Long
rcnt = Sheets("existing").Range("A" & Rows.Count).End(xlUp).Row
For c = 2 To rcnt
Dim iNum(1 To 8) As String
iNum(1) = TextBox24.Value
iNum(2) = TextBox25.Value
iNum(3) = TextBox26.Value
'check if article exists
ActiveWorkbook.Sheets("existing").Activate
If Sheets("existing").Range("A" & c).Value = iNum(1) & iNum(2) & "-" & iNum(3) Then
TextBox26.Value = TextBox26.Value + 1
iNum(3) = TextBox26.Value
End If
Next c
'create article number
TextBox8.Value = iNum(1) + iNum(2) + "-" + iNum(3)
'select first column
Range("A1").Select