I have this VBA program that I created a long time ago. In its original document it work perfectly and outputs something that looks like the following:
However, when I copy the input sheet and VBA code to a new document that set up exactly the same it gives me a
Runtime error 13: type mismatch error
on the line that says EndTime = ActiveSheet.Cells(RowIndex, VAR5) about halfway down the code.
Public RESOL As Single
Public StepRow As Integer 'this is the start ROW for the STEP numbers
Public StepColumn As Integer 'this is the COLUMN for the STEP numbers
Public VAR3 As Integer 'this is the COLUMN for ABSOLUTE START
Public VAR4 As Integer 'this is the COLUMN for LINK
Public VAR5 As Integer 'this is the COLUMN for DURATION
Public VAR6 As Integer 'this is the COLUMN for the first time period
Public VAR7 As Integer ' this is the ROW for the labels
Public RowPos As Single
Public TotalTime As Single
Public x1 As Single
Public RowIndex As Integer
Public LastColumn As Integer
Public StartTime As Single
Public EndTime As Single
Public WindowSize As Single
Sub Chart()
StepRow = 5 ' starting row for step numbers
StepColumn = 2 ' this is the COLUMN for the STEP numbers
VAR3 = 4 ' this is the COLUMN for ABSOLUTE START
VAR4 = 5 ' this is the COLUMN for LINK
VAR5 = 6 ' this is the COLUMN for DURATION
VAR6 = 11 ' this is the COLUMN for the first time period
VAR7 = 3 ' this is the ROW for the labels.
RESOL = ActiveSheet.Cells(1, VAR3)
'when the resolution to .01 if less than .01
If RESOL < 0.01 Then
MsgBox ("Grid resolution must be at least .01")
Exit Sub
End If
LastColumn = VAR6
TotalTime = 0
RowIndex = StepRow
CheckNum = 1
Do
x = ActiveSheet.Cells(RowIndex, StepColumn)
' bomb if no step number present
If IsNumeric(x) = False Then
MsgBox ("Couldn't find a step number at position " & CheckNum)
Exit Sub
End If
If x < 1 Then
LastNum = CheckNum - 1
Exit Do
End If
If x <> CheckNum Then
MsgBox ("Step number does not match position" & CheckNum)
Exit Sub
End If
RowIndex = RowIndex + 1
CheckNum = CheckNum + 1
Loop
ActiveSheet.Lines.Delete
ActiveSheet.Range(Cells(VAR7, VAR6), Cells(VAR7, 256)).ClearContents
Application.ScreenUpdating = False
WindowSize = ActiveWindow.Zoom
ActiveWindow.Zoom = 100
RowIndex = StepRow
CheckNum = 1
Do
LinkPos = ActiveSheet.Cells(RowIndex, VAR4)
If Val(LinkPos) > LastNum Then
MsgBox ("Illegal LINK number for step " + CheckNum)
ActiveWindow.Zoom = WindowSize
Application.ScreenUpdating = True
Exit Sub
End If
If Val(LinkPos) < 1 Then
ActiveSheet.Cells(RowIndex, VAR4).Formula = Empty
End If
If Val(LinkPos) > 0 And Val(LinkPos) <= LastNum Then
ActiveSheet.Cells(RowIndex, VAR3).Formula = "NA"
End If
If CheckNum = LastNum Then
Exit Do
End If
CheckNum = CheckNum + 1
RowIndex = RowIndex + 1
Loop
CompletedSteps = 0
RowIndex = StepRow
CheckNum = 1
Do
AbsPos = ActiveSheet.Cells(RowIndex, VAR3)
If AbsPos <> "NA" And IsNumeric(AbsPos) = True Then
StartTime = Val(AbsPos)
EndTime = ActiveSheet.Cells(RowIndex, VAR5)
EndTime = EndTime + StartTime
Run ("DrawLine")
CompletedSteps = CompletedSteps + 1
End If
If CheckNum = LastNum Then
Exit Do
End If
CheckNum = CheckNum + 1
RowIndex = RowIndex + 1
Loop
NoOfTries = 1
Do
If CompletedSteps = LastNum Then
Exit Do
End If
RowIndex = StepRow
CheckNum = 1
Do
LinkTo = ActiveSheet.Cells(RowIndex, VAR4)
If Val(LinkTo) >= 1 And Val(LinkTo) <= LastNum Then
AbsPos = ActiveSheet.Cells(StepRow - 1 + LinkTo, VAR3)
If AbsPos <> "NA" And IsNumeric(AbsPos) = True Then
DurPos = ActiveSheet.Cells(StepRow - 1 + LinkTo, VAR5)
AbsPos = AbsPos + DurPos
StartTime = Val(AbsPos)
EndTime = ActiveSheet.Cells(RowIndex, VAR5)
EndTime = EndTime + StartTime
ActiveSheet.Cells(RowIndex, VAR3).Formula = StartTime
Run ("DrawLine")
Top1 = ActiveSheet.Cells(StepRow - 1 + LinkTo, VAR6).Top
Top2 = ActiveSheet.Cells(StepRow + LinkTo, VAR6).Top
RowPos2 = Top1 + ((Top2 - Top1) / 2)
Set mySheet = ActiveSheet
With mySheet.Shapes.AddLine(x1, RowPos, x1, RowPos2).Line
.DashStyle = msoLineDash
.ForeColor.RGB = RGB(0, 0, 0)
End With
CompletedSteps = CompletedSteps + 1
End If
End If
If CheckNum = LastNum Then
Exit Do
End If
CheckNum = CheckNum + 1
RowIndex = RowIndex + 1
Loop
If NoOfTries = LastNum Then
Exit Do
End If
NoOfTries = NoOfTries + 1
Loop
RowIndex = StepRow
CheckNum = 1
Do
LinkPos = ActiveSheet.Cells(RowIndex, VAR4)
If Val(LinkPos) > 0 And Val(LinkPos) <= LastNum Then
ActiveSheet.Cells(RowIndex, VAR3).Formula = Empty
End If
If CheckNum = LastNum Then
Exit Do
End If
CheckNum = CheckNum + 1
RowIndex = RowIndex + 1
Loop
CheckCol = VAR6
ColVal = RESOL
Do
ActiveSheet.Cells(VAR7, CheckCol).Formula = ColVal
If CheckCol >= LastColumn Then
Exit Do
End If
ColVal = ColVal + RESOL
CheckCol = CheckCol + 1
Loop
ActiveSheet.Cells(2, VAR3).Formula = TotalTime
Range("A1").Select
ActiveWindow.Zoom = WindowSize
Application.ScreenUpdating = True
End Sub
Sub Drawline()
If EndTime > TotalTime Then
TotalTime = EndTime
End If
Top1 = ActiveSheet.Cells(RowIndex, VAR6).Top
Top2 = ActiveSheet.Cells(RowIndex + 1, VAR6).Top
RowPos = Top1 + ((Top2 - Top1) / 2)
CheckCol = VAR6
ColTime = 0
Do
x1 = ActiveSheet.Cells(RowIndex, CheckCol).Left
If ColTime = StartTime Then
Exit Do
End If
If ColTime > StartTime Then
x2 = ActiveSheet.Cells(RowIndex, CheckCol - 1).Left
Span = x1 - x2
Differencial = (ColTime - StartTime) / RESOL
TimeOffset = Differencial * Span
x1 = x1 - TimeOffset
Exit Do
End If
ColTime = ColTime + RESOL
CheckCol = CheckCol + 1
Loop
CheckCol = VAR6
ColTime = 0
Do
y1 = ActiveSheet.Cells(RowIndex, CheckCol).Left
If ColTime = EndTime Then
Exit Do
End If
If ColTime > EndTime Then
y2 = ActiveSheet.Cells(RowIndex, CheckCol - 1).Left
Span = y1 - y2
Differencial = (ColTime - EndTime) / RESOL
TimeOffset = Differencial * Span
y1 = y1 - TimeOffset
Exit Do
End If
ColTime = ColTime + RESOL
CheckCol = CheckCol + 1
Loop
If CheckCol > LastColumn Then
LastColumn = CheckCol
End If
Set mySheet = ActiveSheet
With mySheet.Shapes.AddLine(x1, RowPos - 2, y1, RowPos - 2).Line
.DashStyle = msoLineSolid
.ForeColor.RGB = RGB(128, 0, 25)
.Weight = xlHairline
End With
With mySheet.Shapes.AddLine(x1, RowPos, y1, RowPos).Line
.DashStyle = msoLineSolid
.ForeColor.RGB = RGB(128, 0, 25)
.Weight = xlThick
End With
With mySheet.Shapes.AddLine(x1, RowPos + 2, y1, RowPos + 2).Line
.DashStyle = msoLineSolid
.ForeColor.RGB = RGB(128, 0, 25)
.Weight = xlHairline
End With
End Sub
Any help would be greatly appreciated. I have the two documents set up exactly the same so I can't figure out why its working on one, but not the other.
Edit: below is the state of the document when it errors out. It added all the "NA" to the start time column, but doesn't do that on the original sheet.
When I comment out the error it works, but prints the following where there are solid bars beneath the gantt chart and the starting bar is solid.
Related
There are some good posts that describe the two major ways of measuring the performance of your code. However, if you have a multi-module project with calls that may execute thousands of sub routine calls at a single operation, it is difficult to pin down where the performance hogs are. How to come about this?
I did write a generic benchmarking code that can be added to any vba project. It works by adding code to each entry and exit point of every sub/function/property to measure the time spent in each sub both as total time as well as time excluding sub-subroutines. This is how to use it:
Create a new module in your project called modBench. Naming is
important.
Copy the code shown below to that module.
Make sure that Microsoft Visual Basic for Application Extensability
is referenced in VBA
Make sure that you allow excel to allow "Trust access to the VBA
project object model" (excel setting in Options=>Trust Center=>Trust
Center Settings=>Macro Settings
Your workbook should be saved as a different name
Run "Start_Benchmark"
Do some tasks. Avoid msg-boxes and similar to show real "cpu-hogs"
Run "End_Benchmark"
A report is generated in the same folder as the workbook.
Code of module "modBench":
Option Explicit
Private Const CLT_1 = " 'CODE INSERTED BY MODBENCH"
Private Const CLT_2 = """ INSERTED BY MODBENCH"
Private Const CLT_3 = " 'PARTIAL CODE """
Private Const CLT_4 = "'MODBENCH TO INSERT PROCEDURE INFO START HERE"
Public Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As Currency) As Long
Public Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As Currency) As Long
Private p_count(10000) As Long
Private p_total_time(10000) As Currency
Private p_module_time(10000) As Currency
Private p_in_time(10000) As Currency
Private p_call_stack(10000) As Long
Private p_call_stack_indx As Long
Private t1 As Currency
Private t2 As Currency
Sub PrintBenchResults()
Dim i As Long, j As Long, dTimerTmp() As Double, lMaxIndx As Long
Dim m_PerfFrequency As Currency
QueryPerformanceFrequency m_PerfFrequency
ReDim dTimerTmp(UBound(dTimer))
For i = 0 To UBound(dTimerTmp)
dTimerTmp(i) = dTimer(i) / m_PerfFrequency * 1000
Next
Do
lMaxIndx = 0
For i = 1 To UBound(dTimerTmp)
If dTimerTmp(i) > dTimerTmp(lMaxIndx) Then lMaxIndx = i
Next
If dTimerTmp(lMaxIndx) < -1000 Then Exit Do
If lCount(lMaxIndx) > 0 Then
Debug.Print Round(dTimerTmp(lMaxIndx), 1) & " ms (" & lCount(lMaxIndx) & " runs) " & vbTab & Round(dTimerTmp(lMaxIndx) / lCount(lMaxIndx), 3) & " ms per run" & vbTab & sProc(lMaxIndx)
Else
Debug.Print Round(dTimerTmp(lMaxIndx), 3) & " ms (" & lCount(lMaxIndx) & " runs) " & vbTab & sProc(lMaxIndx)
End If
dTimerTmp(lMaxIndx) = -1001
Loop
End Sub
Sub p_out(P_id As Long)
Dim time_out As Currency
QueryPerformanceCounter time_out
p_call_stack_indx = p_call_stack_indx - 1
t1 = time_out - p_in_time(p_call_stack_indx)
p_total_time(P_id) = p_total_time(P_id) + t1
p_module_time(P_id) = p_module_time(P_id) + t1
If p_call_stack_indx > 0 Then
p_module_time(p_call_stack(p_call_stack_indx - 1)) = p_module_time(p_call_stack(p_call_stack_indx - 1)) - t1
End If
End Sub
Sub p_in(P_id As Long)
Dim time_in As Currency
QueryPerformanceCounter time_in
p_in_time(p_call_stack_indx) = time_in
p_call_stack(p_call_stack_indx) = P_id
p_call_stack_indx = p_call_stack_indx + 1
p_count(P_id) = p_count(P_id) + 1
End Sub
Sub Start_Benchmark()
Dim VBComp As VBIDE.VBComponent, ThisModule As VBIDE.CodeModule, i As Long, j As Long, ProcStartOffset As Long
Dim p_index As Long
Dim ProcedureKind As Long
Dim ProcedureName As String
Dim ProcStart As Long, ProcEnd As Long, ProcCodeEnd As Long
Dim p_line As String, lPos As Long, p_type As String
Dim p_code_insert() As String: ReDim p_code_insert(0)
RemoveBenchCode
p_index = 0
For Each VBComp In ThisWorkbook.VBProject.VBComponents
With VBComp.CodeModule
If .Name <> "modBench" Then
i = .CountOfDeclarationLines + 1
While i < .CountOfLines
ProcedureName = .ProcOfLine(i, ProcedureKind)
ProcStart = .ProcBodyLine(ProcedureName, ProcedureKind)
ProcStartOffset = 1
While Right(RTrim(.Lines(ProcStart + ProcStartOffset - 1, 1)), 1) = "_"
ProcStartOffset = ProcStartOffset + 1
Wend
.InsertLines ProcStart + ProcStartOffset, " p_in " & p_index & CLT_1
ProcEnd = i + .ProcCountLines(ProcedureName, ProcedureKind) - 1
ProcCodeEnd = ProcEnd
While Left(LTrim(.Lines(ProcCodeEnd, 1)), 4) <> "End "
ProcCodeEnd = ProcCodeEnd - 1
Wend
For j = ProcStart + ProcStartOffset To ProcCodeEnd - 1
p_line = " " & .Lines(j, 1) & " "
lPos = InStr(p_line, " Exit Function "): p_type = " Exit Function "
If lPos = 0 Then lPos = InStr(p_line, " Exit Sub "): p_type = " Exit Sub "
If lPos = 0 Then lPos = InStr(p_line, " Exit Property "): p_type = " Exit Property "
If lPos > 0 Then
p_line = Mid(p_line, 2, lPos - 1) & "modBench.p_out " & p_index & ": " & Mid(p_line, lPos + 1, Len(p_line)) & CLT_3 & "modBench.p_out " & p_index & ": " & CLT_2
.DeleteLines j, 1
.InsertLines j, p_line
End If
Next
.InsertLines ProcCodeEnd, " p_out " & p_index & CLT_1
ProcCodeEnd = ProcCodeEnd + 1
ProcEnd = ProcEnd + 1
i = ProcEnd + 1
ReDim Preserve p_code_insert(p_index + 2)
p_code_insert(p_index + 2) = " p_names(" & p_index & ") = """ & VBComp.Name & "." & ProcedureName & """"
p_index = p_index + 1
Wend
Else
Set ThisModule = VBComp.CodeModule
End If
End With
Next
p_index = p_index - 1
If p_index < 0 Then Exit Sub
p_code_insert(0) = " p_max_index = " & p_index
p_code_insert(1) = " ReDim p_names(" & p_index & ") As String"
For i = 0 To UBound(p_code_insert)
p_code_insert(i) = p_code_insert(i) & Space(99 - Len(p_code_insert(i))) & CLT_1
Next
With ThisModule
i = .CountOfDeclarationLines + 1
While i < .CountOfLines
If Right(.Lines(i, 1), Len(CLT_4)) = CLT_4 Then
i = i + 1
.InsertLines i, Join(p_code_insert, vbCrLf)
Exit Sub
End If
i = i + 1
Wend
End With
End Sub
Sub RemoveBenchCode()
Dim VBComp As VBIDE.VBComponent, i As Long, p_line As String, p_part As String, cit_pos As Long
For Each VBComp In ThisWorkbook.VBProject.VBComponents
With VBComp.CodeModule
i = 1
While i < .CountOfLines
p_line = .Lines(i, 1)
If Right(p_line, Len(CLT_1)) = CLT_1 Then
.DeleteLines i, 1
i = i - 1
ElseIf Right(p_line, Len(CLT_2)) = CLT_2 Then
p_part = Left(p_line, Len(p_line) - Len(CLT_2))
cit_pos = InStrRev(p_part, """")
If cit_pos > 0 Then
If Right(Left(p_part, cit_pos), Len(CLT_3)) = CLT_3 Then
p_part = Right(p_part, Len(p_part) - cit_pos)
p_line = Left(p_line, Len(p_line) - Len(CLT_2) - Len(CLT_3) - Len(p_part))
p_line = Replace(p_line, p_part, "")
.DeleteLines i, 1
.InsertLines i, p_line
End If
End If
End If
i = i + 1
Wend
End With
Next
End Sub
Sub End_Benchmark()
Dim p_max_index As Long, i As Long, p_names() As String, sOutputFile As String, WBout As Workbook, WSout As Worksheet
Dim fso As Object
Dim SortOrder() As Long, tmpSort As Long, CntUsed As Long
Dim IsSorted As Boolean
p_max_index = 0
ReDim p_names(0) As String
'MODBENCH TO INSERT PROCEDURE INFO START HERE
CntUsed = 0
ReDim SortOrder(0) As Long
For i = 0 To p_max_index
If p_count(i) > 0 Then
ReDim Preserve SortOrder(CntUsed)
SortOrder(CntUsed) = i
CntUsed = CntUsed + 1
End If
Next
IsSorted = False
While Not IsSorted
IsSorted = True
i = 0
While i <= CntUsed - 2
If p_module_time(SortOrder(i)) < p_module_time(SortOrder(i + 1)) Then
IsSorted = False
tmpSort = SortOrder(i)
SortOrder(i) = SortOrder(i + 1)
SortOrder(i + 1) = tmpSort
End If
i = i + 1
Wend
Wend
sOutputFile = ThisWorkbook.Path & "\Benchmark results for " & Left(ThisWorkbook.Name, InStrRev(ThisWorkbook.Name, ".")) & "xlsx"
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists(sOutputFile) Then
Application.DisplayAlerts = False
Set WBout = Application.Workbooks.Open(sOutputFile)
Application.DisplayAlerts = True
Else
Set WBout = Application.Workbooks.Add
WBout.SaveAs sOutputFile
End If
Set WSout = WBout.Worksheets(1)
FormatBlock WSout, CntUsed
WSout.Cells(1, 1).Value = "Benchmark of " & ThisWorkbook.Name
WSout.Cells(1, 6).Value = "D_Out:" & p_call_stack_indx
WSout.Cells(2, 1).Value = Now()
WSout.Cells(3, 3).Value = "Time including subroutines"
WSout.Cells(3, 5).Value = "Time excluding subroutines"
WSout.Cells(4, 1).Value = "Module"
WSout.Cells(4, 2).Value = "No. runs"
WSout.Cells(4, 3).Value = "Total run time"
WSout.Cells(4, 4).Value = "Avg. time/run"
WSout.Cells(4, 5).Value = "Total run time"
WSout.Cells(4, 6).Value = "Avg. time/run"
For i = 0 To CntUsed - 1
WSout.Cells(5 + i, 1).Value = p_names(SortOrder(i))
WSout.Cells(5 + i, 2).Value = p_count(SortOrder(i))
FillWithFormat WSout.Cells(5 + i, 3), p_total_time(SortOrder(i))
FillWithFormat WSout.Cells(5 + i, 4), p_total_time(SortOrder(i)) / p_count(SortOrder(i))
FillWithFormat WSout.Cells(5 + i, 5), p_module_time(SortOrder(i))
FillWithFormat WSout.Cells(5 + i, 6), p_module_time(SortOrder(i)) / p_count(SortOrder(i))
Next
WBout.Save
RemoveBenchCode
'WBout.Close True
End Sub
Public Sub FillWithFormat(rIn As Range, cCounter As Currency)
Dim m_PerfFrequency As Currency, dTime As Double, unit As String, lDigits As Long, lMega As Long
QueryPerformanceFrequency m_PerfFrequency
dTime = cCounter / m_PerfFrequency * 1000000
rIn.Value = dTime
If dTime = 0 Then
rIn.NumberFormat = "0"" s"""
Else
lMega = Int(Log(dTime) / Log(1000))
If lMega < 0 Then lMega = 0
lDigits = 3 * lMega + 2 - Int(Log(dTime) / Log(10))
Select Case lMega
Case 0: unit = "µs"
Case 1: unit = "ms"
Case 2: unit = "s"
Case 3: unit = "ks"
End Select
If lDigits <= 0 Then
rIn.NumberFormat = "0" & String(lMega, ",") & """ " & unit & """"
Else
rIn.NumberFormat = "0." & String(lDigits, "0") & String(lMega, ",") & """ " & unit & """"
End If
End If
End Sub
Public Function TimestringFromCounter(cCounter As Currency) As String
Dim m_PerfFrequency As Currency, dTime As Double, unit As String, lDigits As Long, sFormatString
QueryPerformanceFrequency m_PerfFrequency
dTime = cCounter / m_PerfFrequency
unit = "s"
If dTime < 1 Then dTime = dTime * 1000: unit = "ms"
If dTime < 1 Then dTime = dTime * 1000: unit = "µs"
If dTime <= 0.005 Then
TimestringFromCounter = "<0.01 µs"
Else
lDigits = 2 - Int(Log(dTime) / Log(10))
If lDigits < 0 Then lDigits = 0
sFormatString = "0"
If lDigits > 0 Then sFormatString = "0." & String(lDigits, "0")
TimestringFromCounter = Replace(Format(dTime, sFormatString) & " " & unit, ",", ".")
End If
End Function
Sub FormatBlock(WS As Worksheet, lModuleLines As Long)
WS.Range(WS.Cells(1, 1), WS.Cells(5 + lModuleLines, 1)).EntireRow.Insert Shift:=xlDown
WS.Columns("A:A").ColumnWidth = 50
WS.Columns("B:B").ColumnWidth = 7.86
WS.Columns("C:F").ColumnWidth = 12.86
WS.Range("A1").Font.Size = 14
WS.Range("A2").NumberFormat = "yyyy/mm/dd hh:mm:ss"
WS.Range("A2").HorizontalAlignment = xlLeft
WS.Range("B:F").HorizontalAlignment = xlCenter
WS.Range("C3:D3").Merge
WS.Range("E3:F3").Merge
With WS.Range("A1:F2").Interior
.ThemeColor = xlThemeColorDark1
.TintAndShade = -4.99893185216834E-02
End With
With WS.Range("A3:F4").Interior
.ThemeColor = xlThemeColorAccent6
.TintAndShade = 0.599993896298105
End With
With WS.Range(WS.Cells(5, 1), WS.Cells(4 + lModuleLines, 6)).Interior
.ThemeColor = xlThemeColorAccent6
.TintAndShade = 0.799981688894314
End With
With WS.Range(WS.Cells(3, 3), WS.Cells(4 + lModuleLines, 4))
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeLeft).Weight = xlThin
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlEdgeRight).Weight = xlThin
End With
With WS.Range(WS.Cells(1, 1), WS.Cells(4 + lModuleLines, 6))
.Borders(xlEdgeLeft).LineStyle = xlContinuous
.Borders(xlEdgeLeft).Weight = xlMedium
.Borders(xlEdgeTop).LineStyle = xlContinuous
.Borders(xlEdgeTop).Weight = xlMedium
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeBottom).Weight = xlMedium
.Borders(xlEdgeRight).LineStyle = xlContinuous
.Borders(xlEdgeRight).Weight = xlMedium
End With
With Range("A2:F2")
.Borders(xlEdgeBottom).LineStyle = xlContinuous
.Borders(xlEdgeBottom).Weight = xlMedium
End With
End Sub
I have this code in which I do some checking to delete items in a table according to their numeration. When debugging the code whenever it reaches the critical line (shown below) it jumps to the respective Excel Objects code of that sheet (shown even lower). I already tested positioning it in different places across the code and using Application.Enableevents = false but it didn't work.
Any suggestions?
First Code:
Sub deleta_linhas()
Dim linha As Integer, coluna As Integer
Dim n_item As Integer, n_prod As Integer
Dim soma As Integer, linha_selecionada As Integer
linha_selecionada = ActiveCell.Row
Dim linha_atual(1 To 2) As Integer, next_line(1 To 2) As Integer, line_before(1 To 2) As Integer
Dim i As Integer
i = 0
Dim novos_numeros As String
' Condição 1 em que há apenas 1.1 e mais nada
If IsEmpty(Cells(36, 1)) = True Then
ActiveCell.EntireRow.Delete
Range("B5").Value = 1
Range("B6").Value = 1
Range("B7").Value = 0
Range("B8").Value = 35
Else
' Condição 2 em que há 1.1, 1.2 e mais ou 1.1, 2.1 e mais
linha_atual(1) = Mid(Cells(linha_selecionada, 1), 1, 1)
linha_atual(2) = Mid(Cells(linha_selecionada, 1), 5, 1)
next_line(1) = Mid(Cells(linha_selecionada + 1, 1), 1, 1)
next_line(2) = Mid(Cells(linha_selecionada + 1, 1), 5, 1)
line_before(1) = Mid(Cells(linha_selecionada - 1, 1), 1, 1)
line_before(2) = Mid(Cells(linha_selecionada - 1, 1), 5, 1)
If linha_atual(1) = next_line(1) = False And linha_atual(2) = next_line(2) Then
Selection.EntireRow.Delete '(THIS IS WHERE IT JUMPS TO EXCEL OBJECTS)
Range("B8").Value = Range("B8").Value - 1
Range("B5").Value = Range("B5").Value - 1
While IsEmpty(Cells(linha_selecionada + i, 1)) = False
n_item = Mid(Cells(linha_selecionada + 1, 1), 1, 1) - 1
novos_numeros = n_item & " . 1"
Cells(linha_selecionada + 1, 1).Value = novos_numeros
i = i + 1
Wend
End If
End If
linha = 36
coluna = 9
soma = 0
Selection.EntireRow.Delete
While IsEmpty(Cells(linha, coluna)) = False
soma = soma + Cells(linha, coluna).Value
linha = linha + 1
Wend
linha = linha + 1
Cells(linha, coluna).Value = soma
End Sub
Code in the Excel Objects (mostly of combobox buttons)
Private Sub ComboBox1_Change()
If ComboBox1.Value = "Fabricação" Then
Rows("41:52").Select
Selection.EntireRow.Hidden = True
Range("B28").Select
Range("B11").Value = "Fabricação"
End If
If ComboBox1.Value = "Nacionalização" Then
Rows("41:52").Select
Selection.EntireRow.Hidden = False
Range("B28").Select
Range("B11").Value = "Nacionalização"
End If
If ComboBox1.Value = "Projeto" Then
Rows("41:52").Select
Selection.EntireRow.Hidden = False
Range("B28").Select
Range("B11").Value = "Projeto"
End If
If ComboBox1.Value = "Manutenção" Then
Rows("41:52").Select
Selection.EntireRow.Hidden = False
Range("B28").Select
Range("B11").Value = "Manutenção"
End If
If ComboBox1.Value = "Industrialização" Then
Rows("41:52").Select
Selection.EntireRow.Hidden = False
Range("B28").Select
Range("B11").Value = "Industrialização"
End If
End Sub
' Lógicas dos tratamentos
Private Sub OptionButton2_Click()
If OptionButton2.Value = True Then
Range("B10").Value = "Tempera"
End If
End Sub
Private Sub OptionButton1_Click()
If OptionButton1.Value = True Then
Range("B10").Value = "Nitretação"
End If
End Sub
Private Sub OptionButton3_Click()
If OptionButton3.Value = True Then
Range("B10").Value = "Cementação"
End If
End Sub
Private Sub OptionButton4_Click()
If OptionButton4.Value = True Then
Range("B10").Value = "---"
End If
End Sub
' FIM
The macro is written to return the number of letter differences (insertions, replacements, or deletions) of two words (case sensitive).
It is suppose to format and output in phrases
1-2 Letters off,
1-2 Letters off, Same Starting Letter,
3-4 Letters off,
3-4 Letters off, Same Starting Letter and
5 or more letters off, CHECK
It is only outputting
1-2 Letters off, Same Starting Letter,
3-4 Letters off, Same Starting Letter and
5 or more Letters off, CHECK
I would like the formatting to stay the same for now.
Sub Test_HW_Formatter()
'declare the variables
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim testNames As Integer
Dim responses As Integer
Dim printRow As Integer
Dim name As String
Dim count As Integer
Dim coding As String
Dim statLetter As Boolean
Dim tempCount As Integer
Dim tempResp As String
'the queues for the entries, the respective counts, and respective codes
Dim words As Object
Set words = CreateObject("System.Collections.Queue")
Dim counts As Object
Set counts = CreateObject("System.Collections.Queue")
Dim codes As Object
Set codes = CreateObject("System.Collections.Queue")
'set the variables
printRow = 3
testNames = Selection.Columns.count
responses = Selection.Rows.count - 1
Cells(4, 3).Value = Selection(4)
startLetter = True
'make the header
Cells(1, 1).Value = "Name"
Cells(1, 2).Value = "Response"
Cells(1, 3).Value = "Count"
Cells(1, 4).Value = "Code"
Cells(1, 5).Value = "Agency close matches"
Cells(1, 6).Value = "N=" + Trim(Str(responses))
Cells(1, 6).Interior.Color = RGB(255, 255, 204)
Cells(1, 6).HorizontalAlignment = xlCenter
For i = 1 To 5
Cells(1, i).Interior.Color = RGB(1, 139, 175)
Cells(1, i).Font.Color = RGB(255, 255, 255)
Cells(1, i).HorizontalAlignment = xlCenter
Next i
'get the information and put it in the queues
For i = 0 To (testNames - 1)
name = Selection(i + 1).Value
For j = 1 To responses
count = 1
If Not Selection(j * testNames + i + 1) = "" Then
For k = 1 To (responses - j)
If Not Selection((j + k) * testNames + i + 1).Value = "" Then
If Trim(UCase(Selection(j * testNames + i + 1).Value)) = Trim(UCase(Selection((j + k) * testNames + i + 1).Value)) Then
count = count + 1
Selection((j + k) * testNames + i + 1).Value = ""
End If
End If
Next k
'get the coding
coding = ""
ld = Levenshtein(name, Trim(UCase(Selection(j * testNames + i + 1))))
If Mid(testName, 1, 1) = Mid(sample, 1, 1) Then
startLetter = True
Else
startLetter = False
End If 'if for starting letter
Select Case ld
Case 0
coding = "Exact Match"
Case 1
If startLetter = True Then
coding = "1-2 Letters off, Same Starting Letter"
Else
coding = "1-2 Letters off"
End If
Case 2
If startLetter = True Then
coding = "1-2 Letters off, Same Starting Letter"
Else
coding = "1-2 Letters off"
End If
Case 3
If startLetter = True Then
coding = "3-4 Letters off, Same Starting Letter"
Else
coding = "3-4 Letters off"
End If
Case 4
If startLetter = True Then
coding = "3-4 Letters off, Same Starting Letter"
Else
coding = "3-4 Letters off"
End If
Case Else
coding = "5 or more Letters off, CHECK"
End Select
'enqueue the values
tempResp = UCase(Mid(Selection(j * testNames + i + 1).Value, 1, 1)) + LCase(Mid(Selection(j * testNames + i + 1).Value, 2, Len(Selection(j * testNames + i + 1).Value)))
words.enqueue (tempResp)
counts.enqueue (count)
codes.enqueue (coding)
End If 'if the cell is not blank
Next j
'print the queues from the ith column
'start the section header
Cells(printRow, 1).Value = name
Cells(printRow, 1).Font.Color = RGB(255, 255, 255)
For k = 1 To 5
Cells(printRow, k).Interior.Color = RGB(1, 139, 175)
Cells(printRow, k).HorizontalAlignment = xlCenter
Next k
tempCount = counts.count
Cells(150, 20 + i).Value = tempCount
For k = 1 To tempCount
Cells(printRow + k, 2).Value = words.dequeue
Cells(printRow + k, 3).Value = counts.dequeue
Cells(printRow + k, 4).Value = codes.dequeue
If Cells(printRow + k, 4).Value = "Exact Match" Then
Cells(printRow + k, 4).Interior.Color = RGB(236, 239, 218)
End If
Next k
printRow = printRow + tempCount + 2
Next i
End Sub
Edited to add counting replicates of the same name, and skip empty values:
Sub Test_HW_Formatter()
Dim arr, numReps As Long, ws As Worksheet, col As Long, c As Range
Dim nm As String, rep As Long, cmp As String
Dim i As Long, dict As Object, tmp
arr = Selection.Value 'inputs
numReps = UBound(arr, 1) - 1 'reps per column
Set ws = Selection.Parent 'sheet with selection
With ws.Range("A1:E1")
.Value = Array("Name", "Response", "Count", "Code", "Agency Close match")
doHeaders .Cells
End With
ws.Range("F1").Value = "N=" & numReps
Set c = ws.Range("A3") 'start of output sections
For col = 1 To UBound(arr, 2) 'loop columns of selection
nm = arr(1, col)
c.Value = nm
doHeaders c.Resize(1, 5) 'format headers
i = 0
Set dict = CreateObject("scripting.dictionary")
For rep = 1 To numReps 'loop values to compare
cmp = arr(rep + 1, col)
If Len(cmp) > 0 Then
If Not dict.exists(cmp) Then
i = i + 1
dict.Add cmp, i
c.Offset(i, 1).Value = cmp
c.Offset(i, 2) = 1
c.Offset(i, 3).Value = MatchCoding(nm, cmp) 'now in separate function
Else
'increment count for existing line
c.Offset(dict(cmp), 2).Value = c.Offset(dict(cmp), 2).Value + 1
End If
End If 'not zero-length
Next rep
Set c = c.Offset(i + 2, 0) 'next set
Next col
End Sub
'return a string summarizing how closeley two terms match
Function MatchCoding(nm As String, cmp As String)
Dim ld As Long, firstMatch As Boolean
firstMatch = (Left(nm, 1) = Left(cmp, 1))
ld = Levenshtein(nm, cmp)
Select Case ld
Case 0: MatchCoding = "Exact Match"
Case 1, 2: MatchCoding = "1-2 Letters off"
Case 3, 4: MatchCoding = "3-4 Letters off"
Case Else: MatchCoding = "5 or more Letters off, CHECK"
End Select
If ld > 0 And ld < 5 Then MatchCoding = MatchCoding & _
IIf(firstMatch, ", Same Starting Letter", "")
End Function
'utility sub for formatting headers
Sub doHeaders(rng As Range)
With rng
.Interior.Color = RGB(1, 139, 175)
.Font.Color = RGB(255, 255, 255)
.HorizontalAlignment = xlCenter
End With
End Sub
I did a vb code which is reading multiple text files from a folder and then parsing specific data from it. In the code I have hard coded a folderpath strPath = "C:\Users\smim\Desktop\Mim\Excel\". Now I would like to be able to choose the folder and files manually instead of hard coding the folder path. Here is my code :
Sub Parse()
Dim ws As Worksheet
Dim MyData As String, strData() As String
Dim WriteToRow As Long, i As Long
Dim strCurrentTxtFile As String
Dim count As Variant, yellow As Variant, red As Variant,
Dim YellowC As Variant,RedC As Variant, filecounter As Variant
Dim strPath As String
Application.ScreenUpdating = False
count = 0
red = 0
yellow = 0
YellowC = 0
RedC = 0
strPath = "C:\Users\smim\Desktop\Mim\Excel\"
'Set Book3 = Sheets("Sheet1")
Set ws = Workbooks.Add(xlWBATWorksheet).Worksheets(1)
MsgBox ("Started")
'~~> Start from Row 1
'WriteToRow = 1
Cells(3, 1) = "Error"
Cells(3, 1).Interior.ColorIndex = 3
Cells(3, 2) = "Warnings"
Cells(3, 2).Interior.ColorIndex = 6
Cells(1, 3) = "Error"
Cells(1, 3).Interior.ColorIndex = 3
Cells(2, 3) = "Warnings"
Cells(2, 3).Interior.ColorIndex = 6
strCurrentTxtFile = Dir(strPath & "test_*.txt")
' MsgBox (strCurrentTxtFile)
'~~> Looping through all text files in a folder
Do While strCurrentTxtFile <> ""
Dim list() As String
'~~> Open the file in 1 go to read it into an array
Open strPath & strCurrentTxtFile For Binary As #1
MyData = Space$(LOF(1))
Get #1, , MyData
Close #1
strData() = Split(MyData, vbLf)
LineCount = UBound(strData)
' MsgBox (LineCount)
'Assigning length of the list array
ReDim Preserve list(LineCount + 1)
For x = 0 To (LineCount - 1)
'For x = LBound(strData) To UBound(strData)
'Parsing each line to get the result only ( after = sign)
s = Split(strData(x), "=")
b = UBound(s)
'MsgBox (s(1))
'Assigning Values to the list array
list(x) = s(1)
Next
'MsgBox ("This is list" & list(2))
'Active Cell 2
Range("A2").Activate
'Get row number
dblRowNo = ActiveCell.Row
'Get col number
dblColNo = ActiveCell.Column
'MsgBox (dblColNo)
' ReDim Preserve list(LineCount)
For i = 0 To (LineCount - 1)
Cells(3, 3 + i + 1).Value = i
'Looping and assigning Values to the Cell
'For i = LBound(strData) To UBound(strData)
tempParsing = Split(list(i), ":")
' MsgBox (tempParsing(0))
If tempParsing(0) > 0 And tempParsing(0) < 10 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 6
yellow = yellow + 1
ElseIf tempParsing(0) >= 10 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 3
red = red + 1
ElseIf tempParsing(0) = 0 Then
Cells(dblRowNo + count + 2, dblColNo + i + 3).Interior.ColorIndex = 0
End If
'Looping and assigning Values to the Cell
' For i = LBound(strData) To UBound(strData)
Cells(dblRowNo + count + 2, dblColNo + 1) = yellow
Cells(dblRowNo + count + 2, dblColNo) = red
Cells(dblRowNo + count + 2, dblColNo + i + 3).Value = list(i)
Next
Cells(3 + count + 1, 3).Value = count
count = count + 1
yellow = 0
red = 0
strCurrentTxtFile = Dir
Loop
For t = 4 To 175
If Cells(t, 1).Value > 0 Then
Cells(t, 1).Interior.ColorIndex = 3
End If
If Cells(t, 2).Value > 0 Then
Cells(t, 2).Interior.ColorIndex = 6
End If
Next
'Cells(9, 1) = "linecount = "
'Cells(9, 2) = LineCount
MsgBox "Done"
For f = 4 To 175
If Cells(f, 4).Interior.ColorIndex = 6 Then
YellowC = YellowC + 1
ElseIf Cells(f, 4).Interior.ColorIndex = 3 Then
RedC = RedC + 1
End If
Next
For g = 4 To 175
If Cells(g, 7).Interior.ColorIndex = 6 Then
YellowC = YellowC + 1
ElseIf Cells(g, 7).Interior.ColorIndex = 3 Then
RedC = RedC + 1
End If
Next
For u = 0 To (LineCount - 1)
Cells(dblRowNo, dblColNo + u + 3) = YellowC
Cells(1, dblColNo + u + 3) = RedC
Next
YellowC = 0
RedC = 0
Application.ScreenUpdating = True
End Sub
I'm trying to write a program for a userform in excel for editing chart title and other things. I want write a code that uses special characters i.e. {like this} and changes the text inside the cutely brackets to subscript and I want to able to do this multiple times:
The following code this but only for the first occurrence.
Public Font_Name As String, Font_Style As String, Half_Height As Integer
Sub CommandButton1_Click()
'********************Define Standardized Plot Settings******************
Font_Name = "Arial"
Font_Style = "Normal"
Title_Font_Size = 28
Axes_Label_Font_Size = 22
Tick_Lable_Font_Size = 20
PlotArea_Border_Color_R = 0
PlotArea_Border_Color_G = 0
PlotArea_Border_Color_B = 0
PlotArea_Border_Weight = 3
PlotArea_Border_Weight_Pass = PlotArea_Border_Weight
Grid_Color_R = 150
Grid_Color_G = 150
Grid_Color_B = 150
Grid_Weight = 2
Grid_Weight_Pass = Grid_Weight
'*****************End Define Standardized Plot Settings*****************
'****************************Format the plot********************************
'----------------------------Format the Title-------------------------------
'*****Searches Char Title for {} and replaces everything indside as subscript***
With ActiveChart
.HasTitle = True
.ChartTitle.Text = Me.Chart_Title.Text
.ChartTitle.Characters.Font.Name = Font_Name
.ChartTitle.Characters.Font.FontStyle = Font_Style
.ChartTitle.Characters.Font.Size = Title_Font_Size 'works
If Me.FontOveride <> "" Then
.ChartTitle.Characters.Font.Size = Me.FontOveride
Else
.ChartTitle.Characters.Font.Size = Title_Font_Size 'works
End If
searchString = Me.Chart_Title.Text
Char1 = "{"
Char2 = "}"
For i = 1 To Len(searchString)
If Mid(searchString, i, 1) = Char1 Then
startPos = i
Exit For
Else:
End If
Next i
For j = 1 To Len(searchString)
If Mid(searchString, j, 1) = Char2 Then
endPos = j
Exit For
Else:
End If
Next j
If startPos >= 1 Or endPos >= 1 Then
.ChartTitle.Characters(startPos, endPos - startPos).Font.Subscript = True
.ChartTitle.Characters(startPos, 1).Delete
.ChartTitle.Characters(endPos - 1, 1).Delete
Else:
End If
End With
'***************************************************************************
'***************************************************************************
'----------------------------Format the X Axis-------------------------------
With ActiveChart.Axes(xlCategory)
.HasTitle = True
.AxisTitle.Characters.Text = Me.X_Axis_Title
.AxisTitle.Characters.Font.Name = Font_Name
.AxisTitle.Characters.Font.FontStyle = Font_Style
.AxisTitle.Characters.Font.Size = Axes_Label_Font_Size
.TickLabels.Font.Name = Font_Name
.TickLabels.Font.FontStyle = Font_Style
.TickLabels.Font.Size = Tick_Lable_Font_Size
.MajorTickMark = xlTickMarkNone
.MinimumScale = Me.X_Axis_Start
.MaximumScale = Me.X_Axis_Stop
.MajorUnit = Me.X_Axis_Step
.CrossesAt = Me.X_Axis_Start
.HasMajorGridlines = True
.MajorGridlines.Border.Color = RGB(Grid_Color_R, Grid_Color_G, Grid_Color_B)
.MajorGridlines.Border.Weight = Grid_Weight_Pass
.Border.Color = vbBlack
'*****Searches X-Axis for {} and replaces everything indside as subscript*******
searchString = Me.X_Axis_Title
Char1 = "{"
Char2 = "}"
For i = 1 To Len(searchString)
If Mid(searchString, i, 1) = Char1 Then
Pos1 = i
Exit For
Else:
'End If
End If
Next i
For j = 1 To Len(searchString)
If Mid(searchString, j, 1) = Char2 Then
Pos2 = j
Exit For
Else:
'End If
End If
Next j
If Pos1 >= 1 And Pos2 >= 1 Then
.AxisTitle.Characters(Pos1, Pos2 - Pos1).Font.Subscript = True
.AxisTitle.Characters(Pos1, 1).Delete
.AxisTitle.Characters(Pos2 - 1, 1).Delete
Else:
End If
End With
'----------------------------Format the Y Axis-------------------------------
With ActiveChart.Axes(xlValue)
.HasTitle = True
.AxisTitle.Characters.Text = Me.Y_Axis_Title
.AxisTitle.Characters.Font.Name = Font_Name
.AxisTitle.Characters.Font.FontStyle = Font_Style
.AxisTitle.Characters.Font.Size = Axes_Label_Font_Size
.TickLabels.Font.Name = Font_Name
.TickLabels.Font.FontStyle = Font_Style
.TickLabels.Font.Size = Tick_Lable_Font_Size
On Error GoTo Skip
Decimal_Position = Len(Me.Y_Axis_Step.Text) - WorksheetFunction.Search(".", Me.Y_Axis_Step.Text)
Format_String = "#,##0." & WorksheetFunction.Rept("0", Decimal_Position)
.TickLabels.NumberFormat = Format_String
GoTo Skip2
Skip:
On Error GoTo 0
.TickLabels.NumberFormat = "#,##0"
Skip2:
.MajorTickMark = xlTickMarkNone
.MinimumScale = Me.Y_Axis_Start
.MaximumScale = Me.Y_Axis_Stop
.MajorUnit = Me.Y_Axis_Step
.CrossesAt = Me.Y_Axis_Start
.HasMajorGridlines = True
.MajorGridlines.Border.Color = RGB(Grid_Color_R, Grid_Color_G, Grid_Color_B)
.MajorGridlines.Border.Weight = Grid_Weight_Pass
.Border.Color = vbBlack
'*****Searches Y Axis for {} and replaces everything indside as subscript*******
searchString = Me.Y_Axis_Title
Char1 = "{"
Char2 = "}"
For i = 1 To Len(searchString)
If Mid(searchString, i, 1) = Char1 Then
Pos3 = i
Exit For
Else:
'End If
End If
Next i
For j = 1 To Len(searchString)
If Mid(searchString, j, 1) = Char2 Then
Pos4 = j
Exit For
Else:
'End If
End If
Next j
If Pos3 >= 1 And Pos4 >= 1 Then
.AxisTitle.Characters(Pos3, Pos4 - Pos3).Font.Subscript = True
.AxisTitle.Characters(Pos3, 1).Delete
.AxisTitle.Characters(Pos4 - 1, 1).Delete
Else:
End If
End With
'****************************End Format the Plot*******************************
You can use regular expressions with the pattern {[\w]*}.
If you want to use early binding, then it requires reference to Microsoft VBScript Regular Expressions 5.5.
RegEx will give you, in addition to other information the start position & length of each substring, which you can then use to apply the subscript or other formatting as required.
Sub regTest()
Dim R As Object 'New RegExp
Dim matches As Object 'MatchCollection
Dim m As Variant
Dim str As String
Set R = CreateObject("VBScript.RegExp")
str = "hello {world} this is my {title}"
R.Pattern = "{[\w]*}"
R.Global = True
R.IgnoreCase = True
If R.test(str) Then
Set matches = R.Execute(str)
For Each m In matches
Debug.Print m.Value
Debug.Print "Starts at: " & m.FirstIndex
Debug.Print "Lenght: " & m.Length
Next
End If
End Sub