Optical Mark Reader SR-410 program to read examination card in vb6 - excel

I am developing a program for marking multiple choice answer sheets. For example:
I'm trying to convert the output of data from the OMR device into a human readable format, e.g. Q1 - 1, Q2 - 2, etc for the example sheet.
My code is:
Private Sub Form_Load()
Screen.MousePointer = 11
MSComm1.Handshaking = comRTS
MSComm1.RTSEnable = True
MSComm1.CommPort = 1
MSComm1.Settings = "19200,E,7,2"
MSComm1.PortOpen = True
MSComm1.InBufferCount = 0
MSComm1.OutBufferCount = 0
Screen.MousePointer = 0
End Sub
Private Sub Command1_Click()
Dim Response As String
Dim TMCount As String
Dim CMode As String
Dim EMode() As String
Dim ReciveCnt As Integer
If MSComm1.DSRHolding = False Then
MsgBox "The device is not turned on" + Chr(&HD) + _
"or no communication cable is connected. !!", 16, "SR-430 Sample Program-1"
Screen.MousePointer = 0
Exit Sub
End If
If MSComm1.CTSHolding = False Then
MsgBox "The device is not in the receivable state. !!", 16, "SR-430 Sample Program-1"
Screen.MousePointer = 0
Exit Sub
End If
MSComm1.Output = Chr(&H18) + Chr(&HD)
Do
DoEvents
Loop Until MSComm1.InBufferCount = 1
Response = MSComm1.Input
If Response <> Chr(&H6) Then
MsgBox "Initialization fails !!"
Screen.MousePointer = 0
Exit Sub
End If
MSComm1.Output = Chr(&H13) + "12" + Chr(&HD)
MSComm1.Output = Chr(&H10) + "T" + Chr(&HD)
MSComm1.Output = Chr(&H2) + "2" + Chr(&HD)
MSComm1.Output = "?" + Chr(&HD)
ReciveCnt = 1
Do
DoEvents
Loop Until MSComm1.InBufferCount = ReciveCnt
Response = MSComm1.Input
If Response <> "0" Then
MsgBox "Error occurs!!" + Chr(&HD) + _
"Read status = " + Response
Screen.MousePointer = 0
Exit Sub
End If
MSComm1.Output = Chr(&H5) + "T" + Chr(&HD)
Do
DoEvents
Loop Until MSComm1.InBufferCount = 3
TMCount = MSComm1.Input
Text1.Text = "Timing mark count : " + TMCount + Chr(&HD) + Chr(&HA)
MSComm1.Output = Chr(&H10) + "C001" + TMCount + Chr(&HD)
Do
DoEvents
Loop Until MSComm1.InBufferCount = 3 * Val(TMCount)
CMode = MSComm1.Input
Text1.Text = Text1.Text + "C Mode : " + CMode + Chr(&HD) + Chr(&HA)
ReDim EMode(Val(TMCount)) As String
Dim DataLength As Integer
Text1.Text = Text1.Text + "E Mode : " + Chr(&HD) + Chr(&HA)
MSComm1.Output = Chr(&H10) + "E001" + TMCount + Chr(&HD)
ReciveCnt = 0
Response = " "
Do
DoEvents
Response = Response + MSComm1.Input
DataLength = InStr(Response, Chr(&HD))
If DataLength <> 0 Then
EMode(ReciveCnt) = Left(Response, DataLength)
Text1.Text = Text1.Text + Format(ReciveCnt + 1, "000") + "-Column:" + EMode(ReciveCnt) + Chr(&HA)
Response = Mid(Response, DataLength + 1)
ReciveCnt = ReciveCnt + 1
End If
Loop Until ReciveCnt = Val(TMCount)
Screen.MousePointer = 0
End Sub
Private Sub Form_Unload(Cancel As Integer)
MSComm1.PortOpen = False
End
End Sub
which gives the result below for the example sheet
Timing mark count : 036
C Mode : 00800500500500500500500500A005011300A8124201402800D1F000000000000000000F1F00000001F000F0006003F000000F000000
E Mode :
001-Column: 8
002-Column:9;
003-Column:9;
004-Column:9;
005-Column:9;
006-Column:9;
007-Column:9;
008-Column:9;
009-Column:8:
010-Column:9;
011-Column:7;
012-Column:23
013-Column:024;
014-Column:25:
015-Column:79
016-Column:68
017-Column:89;
018-Column:34567
019-Column:
020-Column:
021-Column:
022-Column:
023-Column:
024-Column:89:;
025-Column:34567
026-Column:
027-Column:
028-Column:34567
029-Column:89:;
030-Column:
031-Column:12
032-Column:234567
033-Column:
034-Column:89:;
035-Column:
036-Column:
How can I modify the code to give the desired output in terms of question / answer

Related

Is there a generic benchmarking code that can be used to pin down performance hogs in your excel/vba code?

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

How to fix error with macros in Excel VBA? ( my code running very slow)

I have a code that I wrote late the other day, however I'm not sure what the issue is that my code runs really slowly when I press the run button.
So, how can I make my code run more smoothly, faster, and open a new workbook to "Export file" without closing my userform1?
seemingly i see a problem with: label19( running text very slow), one with commnand applicationt ( countdown time ) and one with button Export file !
This is my code in userform1:
Private Sub CommandButton1_Click()
UserForm1.Label5.Caption = Label5.Caption + 1
Label6 = Label4.Caption - Label5.Caption
If UserForm1.Label4.Caption <> 0 Then
Label10 = ((Label5.Caption / Label4.Caption) * 100) & "%"
Else
End If
End Sub
Private Sub CommandButton2_Click()
UserForm1.Label5.Caption = Label5.Caption - 1
Label6 = Label4.Caption - Label5.Caption
If UserForm1.Label4.Caption <> 0 Then
Label10 = ((Label5.Caption / Label4.Caption) * 100) & "%"
Else
End If
End Sub
Private Sub CommandButton5_Click()
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("report")
Dim lr As Long
lr = Application.WorksheetFunction.CountA(sh.Range("A:A"))
sh.Range("A" & lr + 1).Value = "=ROW()-1"
sh.Range("B" & lr + 1).Value = Me.Label4.Caption
sh.Range("C" & lr + 1).Value = Me.Label5.Caption
sh.Range("D" & lr + 1).Value = Me.Label6.Caption
sh.Range("E" & lr + 1).Value = Me.Label10.Caption
sh.Range("F" & lr + 1).Value = Me.Label1.Caption
sh.Range("G" & lr + 1).Value = Me.Label3.Caption
MsgBox "Data added successfully", vbInformation
sh.Range("A1").Value = "Nber"
sh.Range("B1").Value = "Target"
sh.Range("C1").Value = "Actual"
sh.Range("D1").Value = "Difer"
sh.Range("E1").Value = "RFT"
sh.Range("F1").Value = "AtTime"
sh.Range("G1").Value = "Date"
End Sub
''''export
Private Sub CommandButton4_Click()
Dim nwb As Workbook
Set nwb = Workbooks.Add
ThisWorkbook.Sheets("report").UsedRange.Copy nwb.Sheets(1).Range("A1")
End Sub
'''Time running
'Dim Berhenti As Boolean
Private Sub Userform_Activate()
Do Until Berhenti
Label1.Caption = Time
Label3.Caption = WorksheetFunction.Text(Date, "[$-0421]DDDD, DD MMMM YYYY")
Label19.Left = Label19.Left - 2
If Label19.Left <= 0 - Label19.Width Then Label19.Left = Me.Width
For i = 1 To 8000000: Next
DoEvents
Loop
End Sub
Private Sub userform_Initialize()
BackColor = RGB(58, 68, 156)
End Sub
Private Sub Userform_QueryClose(cancel As Integer, CloseMode As Integer)
Berhenti = True
End Sub
Private Sub Label4_Click()
UserForm1.Label4.Caption = TextBox1.Text
End Sub
Private Sub TextBox1_Change()
On Error Resume Next
Label4 = TextBox1.Text
Label6 = Label4.Caption - Label5.Caption
Label10 = ((Label5.Caption / Label4.Caption) * 100) & "%"
End Sub
Private Sub CommandButton3_Click()
Run_time
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' code in module:
'''Count down
Sub Run_time()
'Application.ScreenUpdating = False
a = UserForm1.TextBox2.Value
b = UserForm1.TextBox3.Value
C = UserForm1.TextBox4.Value
d = UserForm1.TextBox5.Value
e = UserForm1.TextBox6.Value
f = UserForm1.TextBox7.Value
n = a * 10 * 60 * 60 + b * 60 * 60 + C * 10 * 60 + d * 60 + e * 10 + f
'Unload Me
UserForm1.Show
UserForm1.Label13.Caption = a & b & ":" & C & d & ":" & e & f
For i = 1 To n
UserForm1.Label1.Caption = Time
Application.Wait (Now + #12:00:01 AM#)
UserForm1.Label3.Caption = WorksheetFunction.Text(Date, "[$-0421]DDDD, DD MMMM YYYY")
'''''cuoi
DoEvents
UserForm1.Label19.Left = UserForm1.Label19.Left - 2
If UserForm1.Label19.Left <= 0 - UserForm1.Label19.Width Then UserForm1.Label19.Left = UserForm1.Label19.Width
For J = 1 To 8000000: Next
UserForm1.Label13.Caption = Format(DateAdd("s", -1, UserForm1.Label13.Caption), " hh:mm:ss")
UserForm1.Label15.Width = 156 - 156 * i / n
'Beep
Next i
End Sub

Array For loop throwing Object variable or with block variable not set

So I have this code that sets object properties of a class in a for loop, saving each object as an element in an array, BREobjects(). The very next code is below and the first BREobjects(i).BREdays is throwing an
Object variable not set error.
It's a Public array so it shouldn't need to be redim'ed or anything. Anyone know what's happening?
Code that sets the object properties:
'creates a new object for each BRE day/time combination
count = 0
For Each i In BREitems
BREdaysString = Split(Cells(i.Row, "c").value, ", ")
For j = LBound(BREdaysString) To UBound(BREdaysString)
count = count + 1
ReDim Preserve BREobjects(count)
Set BREobjects(count) = New BREpptObjects
BREobjects(count).BREname = Cells(i.Row, "a").value
BREobjects(count).BREcategory = Cells(i.Row, "b").value
BREobjects(count).BREstartTime = Cells(i.Row, "d").value
BREobjects(count).BRElength = Cells(i.Row, "e").value
BREobjects(count).BREtimeRight = Right(Cells(i.Row, "d").value, 2)
BREobjects(count).BREdays = BREdaysString(j)
'Sets the start row number accounting for BREs that start on the half hour
If BREobjects(count).BREtimeRight = 0 Then
BREobjects(count).BREstartRow = (Cells(i.Row, "d").value / 100) + 3
BREobjects(count).BREremainder = 0
ElseIf BREobjects(count).BREtimeRight <> 0 Then
BREobjects(count).BREstartRow = ((Cells(i.Row, "d").value - BREobjects(count).BREtimeRight) / 100) + 3
BREobjects(count).BREremainder = 1
End If
'determines the row the BRE ends in
If BREobjects(count).BRElength - Fix(BREobjects(count).BRElength) = 0 Then
BREobjects(count).BREendRow = BREobjects(count).BREstartRow + BREobjects(count).BRElength - 1
ElseIf BREobjects(count).BRElength - Fix(BREobjects(count).BRElength) > 0 Or BREobjects(count).BREremainder = 1 Then
BREobjects(count).BREendRow = BREobjects(count).BREstartRow + Fix(BREobjects(count).BRElength)
End If
If BREobjects(count).BREremainder = 1 And BREobjects(count).BRElength >= 1 Then
BREobjects(count).BREendRow = BREobjects(count).BREendRow + 1
End If
'sets the end time
If BREobjects(count).BRElength - Fix(BREobjects(count).BRElength) = 0 Then
BREobjects(count).BREendTime = BREobjects(count).BREstartTime + (100 * BREobjects(count).BRElength)
ElseIf BREobjects(count).BRElength - Fix(BREobjects(count).BRElength) > 0 Then
BREtimeRight = Right(BREobjects(count).BRElength, 2)
BREobjects(count).BREendTime = BREobjects(count).BREstartTime + (100 * Fix(BREobjects(count).BRElength)) + (BREtimeRight * 60)
End If
BREobjects(count).BREID = BREobjects(count).BREname & " " & BREobjects(count).BREdays & " " & _
BREobjects(count).BREstartTime & " " & BREobjects(count).BREendTime & " " & BREobjects(count).BRElength
Next j
Erase BREdaysString
Next i
'This loop throws an Object variable or with block variable not set error.
'Thrown on the array in the line BREdays = BREobjects(i).BREdays.
Back:
For i = LBound(BREobjects) To UBound(BREobjects)
Dim BREdays As String
BREdays = BREobjects(i).BREdays
If FiveDay = True And BREdays = "Saturday" Or BREdays = "Sunday" Then
Call DeleteElement(i, BREobjects()) 'Deletes the BREppt Object from the BREobjects array
ReDim Preserve BREobjects(UBound(BREobjects) - 1) 'Shrinks the array by one, removing the last one
GoTo Back 'Restarts the loop because the UBound has changed
End If
Debug.Print BREobjects(i).BREID
Next i
If you were to refactor you code using a collection and move some of the property setting to the class module it could reduce the code to something like this.
Sub ExportToPPTButton_Click()
Dim wb As Workbook, ws As Worksheet, iLastRow As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
iLastRow = ws.Cells(Rows.count, 1).End(xlUp).Row
Dim BREobjects As New Collection
Dim obj As BREpptObjects2, arDays As Variant
Dim i As Long, dow As Variant, sKey As String, s As String
Dim FiveDays As Boolean
' dictionary to count multiple day/time
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
FiveDays = True
For i = 5 To iLastRow
s = ws.Cells(i, "D")
s = Replace(s, " ", "") 'remove spaces
arDays = Split(s, ",")
For Each dow In arDays
s = LCase(Left(dow, 3))
If (FiveDays = True) And (s = "sat" Or s = "sun") Then
' skip weekends
Else
Set obj = New BREpptObjects2
obj.BREDays = dow
obj.initialise ws.Cells(i, 1)
' avoid duplicate day/time
sKey = obj.BREDays & obj.BREstartTime
obj.BREpic = dict(sKey) + 0
dict(sKey) = dict(sKey) + 1
' add to collection
BREobjects.Add obj, obj.BREID
End If
Next
Next
' set total objects in cell
For Each obj In BREobjects
sKey = obj.BREDays & obj.BREstartTime
obj.BREobjInCell = dict(sKey)
Next
MsgBox BREobjects.count & " objects added to collection"
For Each obj In BREobjects
obj.dump ' debug.print objects
Next
End Sub
Note : I used Public here for demo but use Private in your code
' class BREpptObjects2
Public BREname As String, BRElocation As String, BREcategory As String
Public BREstartTime As String, BREendTime As String
Public BRElength As Double
Public BREDays As String, BREID As String, BREStartRow, BREEndRow
Public BREobjInCell As Integer, BREpic As Integer
Sub initialise(rng As Range)
Dim StartHour As Integer, StartMin As Integer
Dim DurHour As Integer, DurMin As Integer
Dim EndHour As Integer, EndMin As Integer
With rng
BREname = .Offset(0, 0).Value ' A
BRElocation = .Offset(0, 1).Value 'B
BREcategory = .Offset(0, 2).Value 'C
BREstartTime = .Offset(0, 4).Value 'E
BRElength = .Offset(0, 5).Value 'F
End With
StartHour = Int(BREstartTime / 100)
StartMin = BREstartTime Mod 100
DurHour = Fix(BRElength)
DurMin = (BRElength - DurHour) * 60
' set end time
EndHour = StartHour + DurHour
EndMin = StartMin + DurMin
If EndMin > 60 Then
EndMin = EndMin - 60
EndHour = EndHour + 1
End If
BREendTime = EndHour * 100 + EndMin
'Sets the start row number accounting for BREs that start on the half hou
BREStartRow = StartHour + 3
BREEndRow = EndHour + 3
BREID = BREname & " " & BREDays & " " & _
BREstartTime & " " & BREendTime & " " & BRElength
End Sub
Sub dump()
Debug.Print "ID [" & BREID & "]"
Debug.Print "StartTime", BREstartTime, "End TIme", BREendTime, "Length", BRElength
Debug.Print "StartRow", BREStartRow, "EndRow", BREEndRow
Debug.Print "pic", BREpic, "objInCell", BREobjInCell
End Sub

How to appear in the right column?

I have a problem which is the data did not appear in the column. Only the first data. Name data should appear at column B9.
And fyi, name will appear at column A in last data.
The data will come out like this;
Where should I need to fix my error?
And the error I think is at this line -
ws.Cells(totalRows + 1, 1) = txtName.Text
Hope anyone of you can help me.
Thank you in advance.
Private Sub cmdAdd_Click()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Master Data")
Dim Addme As Range, str As String, totalRows As Long
Set Addme = ws.Cells(ws.Rows.Count, 3).End(xlUp).Offset(1, 0)
Application.ScreenUpdating = False
If Me.txtName = "" Or Me.cboAmount = "" Or Me.cboCeti = "" Then
MsgBox "There is insufficient data, Please return and add the needed information"
Exit Sub
End If
totalRows = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
totalRows = Application.WorksheetFunction.Max(totalRows, 3)
ws.Cells(totalRows + 1, 1) = txtName.Text
If cbWhatsapp.Value = True Then
str = "Whatsapp, "
End If
If cbSMS.Value = True Then
str = str & "SMS, "
End If
If cbEmail.Value = True Then
str = str & "Email, "
End If
If cbFacebook.Value = True Then
str = str & "Facebook, "
End If
If cbPhoneCall.Value = True Then
str = str & "Phone Call, "
End If
str = Left(str, Len(str) - 2)
ws.Cells(totalRows + 1, 2) = str
If optYes.Value = True Then
ws.Cells(totalRows + 1, 3) = "Yes"
ElseIf optNo.Value = True Then
ws.Cells(totalRows + 1, 3) = "No"
End If
ws.Cells(totalRows + 1, 4) = cboAmount.Value
ws.Cells(totalRows + 1, 5) = cboCeti.Value
ws.Cells(totalRows + 1, 6) = txtPhone.Text
ws.Cells(totalRows + 1, 7) = txtEmail.Text
ws.Range("B9:H10000").Sort Key1:=Range("F9"), Order1:=xlAscending, Header:=xlGuess
MsgBox "Your data was successfully added"
Sheet1.Select
On Error GoTo 0
Exit Sub
End Sub

Need to choose files manually instead of directing the vb code to a folderpath

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

Resources