How to do an infinite loop with Do While VBA - excel

I have a column in excel with values and I would like that when the code run through all the cells it starts again, at the cell A2.
The code works smooth, I'm only having trouble to keep the loop going on.
Sub Loopall()
i = 2
Do While Cells(i, 1) <> ""
Range("A2").Select
Session.FindById("wnd[0]").maximize
Session.FindById("wnd[0]/tbar[0]/okcd").Text = "fbl5n"
Session.FindById("wnd[0]").sendVKey 0
Session.FindById("wnd[0]/usr/ctxtDD_KUNNR-LOW").Text = Cells(i, 1)
Session.FindById("wnd[0]").sendVKey 8
Application.Wait (Now + TimeValue("0:00:02"))
Session.FindById("wnd[0]").sendVKey 3
i = i + 1
If Cells(i, 1) <> "" Then
i = 2
Else
End If
Loop
End sub
I've tried to place the if statement inside the loop, but then the code only reads the first cell. When placing the if outside the loop the code doesn't start the loop again when the cells are empty.

If Cells(i, 1) <> "" Then is restarting your loop when the cell is not blank, which seems like the opposite of what you'd want?
Sub Loopall()
Const START_ROW as Long = 2
i = START_ROW
Do
Session.FindById("wnd[0]").maximize
Session.FindById("wnd[0]/tbar[0]/okcd").Text = "fbl5n"
Session.FindById("wnd[0]").sendVKey 0
Session.FindById("wnd[0]/usr/ctxtDD_KUNNR-LOW").Text = Cells(i, 1)
Session.FindById("wnd[0]").sendVKey 8
Application.Wait (Now + TimeValue("0:00:02"))
Session.FindById("wnd[0]").sendVKey 3
i = i + 1
If Len(Cells(i, 1)) = 0 Then i = START_ROW
Loop
End sub
Probably want to add in some way to escape the loop...

Related

Excel VBA Listbox displays more times than expected

My macro goes through all data rows on a specific sheet. Currently there are 6 rows. The first row is a negative number and the 2nd row is a positive number (debit and credit).
The macro reviews each row and displays a list box for the user to make a selection. Then it goes through the next row and does the same thing. I'm expecting the listbox to display 6 times, once for each row of data.
The problem I'm having is that the listbox is displaying 7 times. 3 times for the first pair or records and twice for the remaining pair of records. I can't figure out why the listbox is displaying the extra time.
Here is the code for the list box:
Private Sub ContinueButton_Click()
If IsNull(ListBox1.Value) Then
MsgBox " Please select the appropriate balance to continue. "
Exit Sub
Else
MyIndex = 0
MyIndex = ListBox1.ListIndex
MyIndex = MyIndex + 1
MyBal = ""
MyBal = APIARArray(MyIndex, 4)
Unload UserForm1
UserForm1.Hide
Sleep 750
End If
End Sub
Private Sub UserForm_Initialize()
UserForm1.Label1.Caption = "Please select the appropriate balance for Unit: " & vUnit
ListBox1.ColumnCount = 4
ListBox1.ColumnWidths = "50;50;75;50"
Dim i As Integer
With ListBox1
w = 1
i = 0
For w = 1 To UBound(APIARArray)
DoEvents
.AddItem
.List(i, 0) = APIARArray(w, 1)
.List(i, 1) = APIARArray(w, 2)
.List(i, 2) = APIARArray(w, 3)
.List(i, 3) = format(APIARArray(w, 4), "#,##0.00;[Red](#,##0.00)")
i = i + 1
Next
End With
UserForm1.Height = 215
UserForm1.Width = 348
ListBox1.SetFocus
End Sub
This is the code that calls the ListBox:
Sub LookForBalance()
Dim r As Integer
Dim APIUnit As String
r = 2
Do Until Len(Trim(Cells(r, 1))) + Len(Trim(Cells(r, 7))) + Len(Trim(Cells(r, 9))) + Len(Trim(Cells(r, 10))) + Len(Trim(Cells(r, 11))) = 0
DoEvents
If Trim(Cells(r, 27)) = "A199" Then
If Cells(r, 29) > 90 Then
APIUnit = ""
vUnit = ""
vUnit = Trim(Cells(r, 11))
If MyCntry = "A1" Then APIUnit = clsAPI.APIARSearch("WWW11", Trim(Cells(r, 11)))
If MyCntry = "A2" Then APIUnit = clsAPI.APIARSearch("WWW12", Trim(Cells(r, 11)))
If InStr(1, APIUnit, "ERROR") > 0 Then
Cells(r, 30) = "Unit Not Found"
Else
If UBound(APIARArray) > 1 Then
Load UserForm1
UserForm1.Show
Cells(r, 30) = MyBal
Else
Cells(r, 30) = APIARArray(1, 4)
End If
End If
End If
End If
r = r + 1
Loop
End Sub
There isn't much code here but I'm not sure what is going on. Any help or suggestions to resolve this issue would be greatly appreciated. Thanks in advance for your help.....

How do I make a loop in SAP VBA script

I've got a problem with a VBA SAP script. I have data in excel and I want to execute the transaction code IW41 by copying and pasting data from Excel. I have all of the data like dates, number of orders, who did it etc in Excel and I want to automate it. I did a loop for variable i but I get an error and I cannot fix it.
Error :
Run-time error '619': Application-defined or object-defined error
Code provided below.
Can you give me some pro tips or help me fix it?
Screen in IW41 where the error occurs:
Code :
Sub ConfirmPM_Nots()
SystemName = "CCP" 'change as needed or use a variable
Transaction = "SESSION_MANAGER" 'change as needed or use a variable
On Error GoTo ErrorHandler:
If Not IsObject(Sap_Applic) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set Sap_Applic = SapGuiAuto.GetScriptingEngine
End If
On Error GoTo 0
koniec:
qConnections = Sap_Applic.Connections.Count
If qConnections = 0 Then
MsgBox "No connection to SAP"
End
End If
bSession = False
For iConnectionCounter = 0 To qConnections - 1
Set Connection = Sap_Applic.Children(Int(iConnectionCounter))
If Not Connection.Description = "" Then
qSessions = Connection.Children.Count
For iSessionCounter = 0 To qSessions - 1
Set session = Connection.Children(Int(iSessionCounter))
If session.info.SystemName <> SystemName Then Exit For
If session.info.Transaction = Transaction Then
bSession = True
Exit For
End If
Next
End If
If bSession Then Exit For
Next
If Not bSession Then
MsgBox SystemName & " not available or free session not available"
End
End If
Do
i = 1
session.findById("wnd[0]").resizeWorkingPane 128, 37, False
session.findById("wnd[0]/tbar[0]/okcd").Text = "iw41"
session.findById("wnd[0]").sendVKey 0
Order = Cells(i, 1)
b = Cells(i, 2)
c = Cells(i, 3)
d = Cells(i, 4)
session.findById("wnd[0]/usr/ctxtCORUF-AUFNR").Text = Order
session.findById("wnd[0]/usr/ctxtCORUF-AUFNR").caretPosition = 7
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/tblSAPLCORUTC_3100/txtAFVGD-VORNR[1,0]").SetFocus
session.findById("wnd[0]/usr/tblSAPLCORUTC_3100/txtAFVGD-VORNR[1,0]").caretPosition = 2
session.findById("wnd[0]").sendVKey 2
session.findById("wnd[0]/usr/chkAFRUD-AUERU").Selected = True
session.findById("wnd[0]/usr/chkAFRUD-LEKNW").Selected = True
session.findById("wnd[0]/usr/ctxtAFRUD-ISDD").Text = c
session.findById("wnd[0]/usr/txtAFRUD-IDAUR").Text = b
session.findById("wnd[0]/usr/ctxtAFRUD-IEDD").Text = c
session.findById("wnd[0]/usr/txtAFRUD-LTXA1").Text = d
session.findById("wnd[0]/usr/txtAFRUD-LTXA1").SetFocus
session.findById("wnd[0]/usr/txtAFRUD-LTXA1").caretPosition = 10
session.findById("wnd[0]/tbar[0]/btn[11]").press
i = i + 1
Loop
Exit Sub
ErrorHandler:
MsgBox "No connection to SAP"
End
End Sub
"iw41" (from session.findById("wnd[0]/tbar[0]/okcd").Text = "iw41") only works if the current screen is the start menu. OK-Code "/niw41" will always work! So this code might work (untested):
Do
i = 1
' session.findById("wnd[0]").resizeWorkingPane 128, 37, False
' iw41 only works in the start menu. OK-Code /niw41 will always work!
session.findById("wnd[0]/tbar[0]/okcd").Text = "/niw41"
session.findById("wnd[0]").sendVKey 0
Order = Cells(i, 1)
b = Cells(i, 2).value
c = Cells(i, 3).value
d = Cells(i, 4).value
session.findById("wnd[0]/usr/ctxtCORUF-AUFNR").Text = Order
' session.findById("wnd[0]/usr/ctxtCORUF-AUFNR").caretPosition = 7
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/tblSAPLCORUTC_3100/txtAFVGD-VORNR[1,0]").SetFocus
' session.findById("wnd[0]/usr/tblSAPLCORUTC_3100/txtAFVGD-VORNR[1,0]").caretPosition = 2
session.findById("wnd[0]").sendVKey 2
session.findById("wnd[0]/usr/chkAFRUD-AUERU").Selected = True
session.findById("wnd[0]/usr/chkAFRUD-LEKNW").Selected = True
session.findById("wnd[0]/usr/ctxtAFRUD-ISDD").Text = c
session.findById("wnd[0]/usr/txtAFRUD-IDAUR").Text = b
session.findById("wnd[0]/usr/ctxtAFRUD-IEDD").Text = c
session.findById("wnd[0]/usr/txtAFRUD-LTXA1").Text = d
' session.findById("wnd[0]/usr/txtAFRUD-LTXA1").SetFocus
' session.findById("wnd[0]/usr/txtAFRUD-LTXA1").caretPosition = 10
session.findById("wnd[0]/tbar[0]/btn[11]").press
i = i + 1
Loop
I also commented the lines with resizeWorkingPane, caretPosition and SetFocus because this is usually not needed. resizeWorkingPane will resize the SAPGUI screen and caretPosition is the position of a cursor within a textbox. Sometimes needed if you want to replace text for example. But in this case certainly not.
NOTE: Your need to exit our Do Loop and place the record pointer i out of the loop. Otherwise i = 1. To exit the loop I often use first blank cell value.
This way you can set the first record to start with, and in most cases i=2 as most sheets have used first row as headers.
i = 1
Do Until Cells(i, 1) = ""
' code
i = i + 1
Loop
When I debugged the code to use it in my own update of Equipment in SAP, I found that our SAP does not have Connection.Description so I just pick up the first session like this.
This worked just fine for me:
Sub SetEQLocations()
' Script written by Svein Aren Hylland 02.12.2022
' Use of VBScript recording from SAP to work with SAP transaction IE02 - Change Equipment.
' The sub will transfere new Location data found in sheet on all visible rows with filter and headers in first row.
' Code will show progress in first column while it updates each EQ in SAP.
'
Sv = MsgBox("This routine work towards SAP IE02 from row 2 - and will update all EQ locations as shown in this sheet.", vbOKCancel)
If Sv = vbCancel Then Exit Sub
SystemName = "KO3" 'change as needed or use a variable
Transaction = "SESSION_MANAGER" 'change as needed or use a variable
On Error GoTo ErrorHandler:
If Not IsObject(Sap_Applic) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set Sap_Applic = SapGuiAuto.GetScriptingEngine
End If
On Error GoTo 0
koniec:
qConnections = Sap_Applic.Connections.Count
If qConnections = 0 Then
MsgBox "No connection to SAP"
End
End If
'MsgBox Sap_Applic.Children(0).info.SystemName
bSession = False
For iConnectionCounter = 0 To qConnections - 1
Set Connection = Sap_Applic.Children(Int(iConnectionCounter))
'MsgBox Connection.Description
'If Not Connection.Description = "" Then
qSessions = Connection.Children.Count
For iSessionCounter = 0 To qSessions - 1
Set Session = Connection.Children(Int(iSessionCounter))
'MsgBox Session.info.SystemName
If Session.info.SystemName <> SystemName Then Exit For
If Session.info.Transaction = Transaction Then
bSession = True
Exit For
End If
Next
'End If
If bSession Then Exit For
Next
If Not bSession Then
MsgBox SystemName & " not available or free session not available"
End
End If
'Stop
Session.findById("wnd[0]").resizeWorkingPane 154, 24, False
Session.findById("wnd[0]/tbar[0]/okcd").Text = "ie02"
Session.findById("wnd[0]").sendVKey 0
i = 2
Do Until Cells(i, 1) = ""
If Cells(i, 1).Rows.Hidden = False Then
EQ = Cells(i, 1)
' Display progress
Cells(i, 1).Select
Cells(i, 1).Interior.Color = vbYellow
' Get data from sheet to be poulated in SAP fields
CostCenter = Cells(i, 14) ' Organization/Cost Center
MainWC = Cells(i, 15) ' Organization/Main Work Center
LocWorkCenter = Cells(i, 16) ' Location/Work Center
LocRoom = Cells(i, 17) ' Location/Room
Session.findById("wnd[0]/usr/ctxtRM63E-EQUNR").Text = EQ
Session.findById("wnd[0]/tbar[0]/btn[0]").press
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02").Select
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/txtITOB-MSGRP").Text = LocRoom
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/txtITOB-MSGRP").SetFocus
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/txtITOB-MSGRP").caretPosition = 6
Session.findById("wnd[0]").sendVKey 0
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/ctxtITOBATTR-ARBPL").Text = LocWorkCenter
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/ctxtITOBATTR-ARBPL").SetFocus
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\02/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1050/ctxtITOBATTR-ARBPL").caretPosition = 6
Session.findById("wnd[0]").sendVKey 0
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\03").Select
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\03/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102A:SAPLITO0:1052/ctxtITOB-KOSTL").Text = CostCenter
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\03/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102B:SAPLITO0:1062/ctxtITOBATTR-GEWRK").Text = MainWC
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\03/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102B:SAPLITO0:1062/ctxtITOBATTR-GEWRK").SetFocus
Session.findById("wnd[0]/usr/tabsTABSTRIP/tabpT\03/ssubSUB_DATA:SAPLITO0:0102/subSUB_0102B:SAPLITO0:1062/ctxtITOBATTR-GEWRK").caretPosition = 6
Session.findById("wnd[0]").sendVKey 0
Session.findById("wnd[0]/tbar[0]/btn[11]").press
End If
i = i + 1
Loop
Exit Sub
ErrorHandler:
MsgBox "No connection to SAP"
End
End Sub

Why does nested loop cause a Run Time Error 13?

I've written a macro that structures a lot of data and saving me for manual punching of numbers etc. The macro is written in stages were each part have been tested isolated and then integrated in loops or to the main code it self - this way each piece of code is tested so it functions accordingly to my intentions.
The goal for this part of code is to cycle through each row in the sheet, if the value of column 9, row I is different from the column 9, row I-1, then it will insert a new row (sum row). This action will be preformed in each worksheet, hence nested loop. When I wrote this macro isolated, without nesting loops, it functioned well.
Edit: To clearify, the code insert a row if and only if Cells(I, PrGr) = Cells(I - 1, PrGr) are unequal. Therefore I ask if they are the same, if they are so, do nothing - else, insert a row (i.e. Cells(I, PrGr) = Cells(I - 1, PrGr) are not equal.)
Running it in a nested loop causes a Run Time Error 13, type mismatch on the line with "If Cells(I, PrGr) = Cells(I - 1, PrGr) Then". In debugger, when I force it to continue, it does what it is supposed to do - creating the sum rows for in every sheet. This happens regardless of which sheet I set as the starting sheet.
I've tried to change the logic of the loop by testing with For Each ws In This.. and with the logic I have now For J = 1 to WS_ant. Both causes the error. I also searched around for clues, but non has come up with any solution appropriate for this problem.
Does someone have a clue to what is happening here, and how to fix it?
The code:
Sub OI_SJ()
'Selects the first sheet
Sheets(1).Activate
'Loop through sheets
Dim J As Integer
Dim WS_ant As Integer
Dim starting_ws As Worksheet
Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
WS_ant = ThisWorkbook.Worksheets.Count
For J = 1 To WS_ant
ThisWorkbook.Worksheets(J).Activate
'If sheet = GRL, then terminate
If ThisWorkbook.Worksheets(J).Name = "LL - Sv" Or ThisWorkbook.Worksheets(J).Name = "RM - Sv" Then
'do something later
ElseIf ThisWorkbook.Worksheets(J).Name = "GRL" Then GoTo Term5
Else
Dim I As Integer
Dim PrGr As Long
PrGr = 9
Set aktivtark = ThisWorkbook.Worksheets(J)
With aktivtark
sistekolonne = aktivtark.Cells(1, .Columns.Count).End(xlToLeft).Column
sisterad = aktivtark.Cells(.Rows.Count, "A").End(xlUp).Row
End With
Application.CutCopyMode = False
Application.ScreenUpdating = False
With aktivtark.Range("A6", Cells(sisterad, sistekolonne))
.RowHeight = 15
End With
Rows(1).RowHeight = 24
For I = 6 To sisterad + 153
If Cells(I, PrGr) = Cells(I - 1, PrGr) Then
ElseIf Cells(I, PrGr) = "PrGr" Then
Else
Rows(I).EntireRow.Insert
Cells(I, 12) = "SUM " & Cells(I - 1, PrGr).Value
Cells(I, 33).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 34).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 35).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 36).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 37).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 38).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 39).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 40).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 41).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 42).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 43).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Cells(I, 44).Formula = "=SUMIF(R7C9:R1500C9,MID(RC12,5,255),R7C:R1500C)"
Rows(I).RowHeight = 17.25
I = I + 1
End If
Next
Application.CutCopyMode = True
Application.ScreenUpdating = True
End If
Cycle:
Next
Term5:
starting_ws.Activate 'activate the worksheet that was originally active
End Sub
With the insight from Vitaliy Prushak's post, I've changed that bit of code from If Cells(I, PrGr) = Cells(I - 1, PrGr) Then to If Cells(I, PrGr).Text = Cells(I - 1, PrGr).Text Then, since the cells contain text. This pushed the problem further down in the code, but it was solved with the same solution.
The macro now runs as it should, thanks for the help.

VBA: Error handling when pasting multiselect listbox values to cell

I need help improving code or if my code is already pretty good, I'd be interested in alternative ways to do it.
What I want to do:
In Excel, I have a userform in which the user types people's name, age, hair color etc. (one person at a time). For something like hair color, I have given 5 pre-defined choices in a listbox and since people can change hair color, multiselect is enabled. The selected hair color (one or multiple) is then pasted to a specific cell.
Problem:
I've struggled a bit with error handling when the user forgets to choose a hair color.
Working code: I did get it to work with the following code
Private Sub cmdSubmit_Click()
Dim cnt As Long
Dim LastRow As Long
Dim s As String
Dim i As Integer
With Me.lbxHair
For i = 0 To .ListCount - 1
If .Selected(i) = True Then
s = s & .List(i) & ","
cnt = cnt + 1
End If
Next i
End With
If cnt = 0 Then
MsgBox "No hair color selected"
Exit Sub
Else
Cells(LastRow + 1, 1).Value = Me.tbxName.Value
Me.tbxName.Value = ""
Me.tbxName.SetFocus
Range("B" & LastRow + 1).Value = Left(s, Len(s) - 1)
On Error Resume Next
End If
End Sub
This is perfectly fine for my purposes, but is there a way to do it without the auxiliary cnt-Variable? I tried this because I've read .ListIndex = -1 means nothing is selected
Non-working code (same variable declaration as above):
With Me.lbxHair
If .ListIndex = -1 Then
MsgBox "No hair color selected"
Exit Sub
Else
For i = 0 To .ListCount - 1
If .Selected(i) = True Then s = s & .List(i) & ","
Next i
End If
End With
Cells(LastRow + 1, 1).Value = Me.tbxName.Value
Me.tbxName.Value = ""
Me.tbxName.SetFocus
Range("B" & LastRow + 1).Value = Left(s, Len(s) - 1)
On Error Resume Next
When trying to not select anything, I get "Run time error '5': Invalid procedure call or argument"
Why? Also, do you have any other suggestions how I could go about this or how I could improve my code?
You can try something like this:
Private Sub cmdSubmit_Click()
Dim LastRow As Long
Dim s As String, sep As String
Dim i As Integer
With Me.lbxHair
For i = 0 To .ListCount - 1
If .Selected(i) = True Then
s = s & sep & .List(i)
sep = ","
End If
Next i
End With
If Len(s) = 0 Then
MsgBox "No hair color selected"
Exit Sub
Else
Cells(LastRow + 1, 1).Value = Me.tbxName.Value
Cells(LastRow + 1, 2).Value = s
Me.tbxName.Value = ""
Me.tbxName.SetFocus
End If
End Sub

Loop that begins at Active Cell

Is it possible to create a loop that will always begin at the active cell?
Here is an example of what I am thinking.
Sub Highlight()
i = 1
Do While Cells(i, ActiveColumn).Value <> ""
If Cells(i, ActiveColumn).Value = 0 Then
Cells(i, ActiveColumn).Value = 3
End If
i = i + 1
Loop
Obviously this code does not work. Cells(i, ActiveColumn) is not a real reference.

Resources