for a while now I've tried to solve the decreased speed issue in my Access application when opening a print preview of certain reports. I've noticed that the slow reports have one thing in common - long, nested if clauses. I tried to search the internet for an answer for this issue, but some of the solutions do not apply to Access VBA or they just aren't possible to implement in the case of my application.
I was wondering if there are some commonly known ways that are used in order to avoid if clause monsters?
EDIT: A snip of code - it mostly handles the structure of the report based on certain conditions.
If (strCcDocNumber <> vbNullString) Then
Dim strUpperPart As String, strLowerPart As String
IDModule.placeIDStringsToPrivateVariables strCcDocNumber, ", "
strUpperPart = IDModule.returnUpper()
strLowerPart = IDModule.returnLower()
txtIDs = strUpperPart & vbCrLf & strLowerPart
Else
txtIDs = " " & vbCrLf & " "
End If
If (strOrderNumber = IO_OrderNumber.OrderNumberCode & "12345") Then
txtIDs = txtIDs
txtIDSpec1 = ModuleIDSpec1.getIDSpec1
txtIDSpec2 = ModuleIDSpec2.getIDSpec2
txtIDSpec1.Height = 330
txtIDSpec2.Height = 330
txtUpperLower = "- Ex" & vbCrLf & "- Ex2" & vbCrLf & vbCrLf & "- Ex3"
On Error Resume Next
For Each c In Me.Controls
If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") Then c.Height = 0
If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") Then c.Visible = False
If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra") Then c.Height = 0
If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra") Then c.Visible = False
If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1Texts") Then c.Visible = True
If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1Texts") Then c.Height = 330
If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C") Then c.Visible = True
If (c.Tag = "IDSpec2Texts" Or c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C") Then c.Height = 330
'+ many more tags
Next
On Error GoTo 0
txtIDSpec1.Visible = True
txtIDSpec2.Visible = True
If (txtIDSpec1 = vbNullString And txtIDSpec2 = vbNullString) Then
txtIDSpec1.Height = 0
txtIDSpec2.Height = 0
txtIDSpec1.Visible = False
txtIDSpec2.Visible = False
End If
Else
'+a lot more similar conditions
EDIT: I remembered which if statements were the most troublesome ones. I think you can't change these ones into select cases or ElseIf statements, because all of the conditions need to be checked...
It goes like this:
If (condition) Then
Do this
If (differentCondition) Then
Do this also
If (completelyDifferentCondition) Then
Do this as well
Else
Do this instead
End If
End If
Else
If (yetAnotherCondition) Then
Do this
Else
Do this instead
End If
End If
I was wondering if there are some commonly known ways that are used in
order to avoid if clause monsters?
First step is to work out what you want to achieve, not how you want to do it. In this context, you want to set height and visibility. From here, you can work out what conditions are required to set this.
When you first do this, you will have some monster clauses - but this is OK because you have not clarified your thinking. Work from an assumption of one state unless proven otherwise. Here is an example:
c.visible = True
If ((c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table") OR (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1TableExtra")) then c.visible = True
Of course, the second line can now be simplified a little bit.
If (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table" Or c.Tag = "IDSpec1TableExtra") then c.visible = True
I also I set marker Booleans - for example:
IsSpecTable = (c.Tag = "IDSpec2Table" Or c.Tag = "IDSpec1Table")
IsMySpecialFriend = (c.Tag = "IDSpec1TextsExtra" And ModuleTarget.TargetGroup <> "23C")
[...]
c.Visible = IsSpecTable Or IsMySpecialFriend
These are a couple of techniques I use to simplify complex business logic. I am also looking at the use of flags, but this means converting the text Tag to an enumerated value (I am doing this in VB.Net). This technique, though, simplifies the expression down to a simple mask with a And or Or operator as appropriate.
Consider using Select Case Statements when you have multiple If Statement based off the same value.
MSDN - Select Case Statement
Executes one of several groups of statements, depending on the value of an expression.
For Each c In Me.Controls
Select Case c.Tag
Case "IDSpec2Table", "IDSpec1Table", "IDSpec1TableExtra"
c.Height = 0
c.Visible = False
Case "IDSpec2Texts", "IDSpec1Texts"
c.Visible = True
c.Height = 330
Case "IDSpec1TextsExtra"
If ModuleTarget.TargetGroup <> "23C" Then
c.Visible = True
c.Height = 330
End If
End Select
Next
Performance: Select Case vs If vs If ElseIf
I mentioned in a comment that using a Select Case is more for readability than performance. Which is correct if we are comparing Select Case and If ElseIf statements (read Which way is faster? If elseif or select case).
Select Case and If ElseIf can be considerably faster than multiple If statements. This is because the VBA evaluates every condition in an If statement and will stop evaluating when one condition is meet in the Select Case statement. Note: not all languages do.
Consider this simple test.
Sub Test()
Debug.Print "Test:If Statement Test:"
If ret(1) = 1 Or ret(2) = 2 Or ret(3) = 3 Or ret(4) = 4 Or ret(5) = 5 Then
End If
Debug.Print vbNewLine; "Test:If ElseIf Statement"
If ret(1) = 1 Or ret(2) = 2 Then
ElseIf ret(3) = 3 Then
ElseIf ret(4) = 4 Then
ElseIf ret(5) = 5 Then
End If
Debug.Print vbNewLine; "Test:Select Case Statement"
Select Case 1
Case ret(1), ret(2)
Case ret(3)
Case ret(4)
Case ret(5)
End Select
End Sub
Function ret(n As Long) As Long
ret = n
Debug.Print n,
End Function
Notice that the If statement had to perform 5 operations even though they were all true. The ElseIf had to perform 2 operations because the first 2 operations were grouped in a single If clause. The Select Case only performed a single operation, even though, two operations were grouped together. This is because the Select Case will always stop evaluating conditions when a single condition is true.
Related
I keep getting the " Else without if" error in VBA when I clearly do not have that issue. Does anyone know how to fix it? It takes me to the elseif statement that begins with elseif memb= "platinum"
Below is my code:
ElseIf memb = "Platinum" Then d = 0.01
ElseIf memb = "Black" Then d = 0.03
End If
If st >= min Then cb = st * d Else cb = 0
End If
If cb >= thresh Then MsgBox ("cb is greater than thresh")
End If
tac = st + cb
Range("B5").Value = st
Range("B7").Value = cb
Range("B9").Value = tac
I'm going to assume your first If statement goes something like this:
If memb = "Gold" Then d = 0.005
ElseIf memb = "Platinum" Then d = 0.01
ElseIf memb = "Black" Then d = 0.03
End If
If some processing is performed on the same line as the Then keyword, VBA treats it as a single, non-nested If statement. This means that anything after that will be treated as a new statement and not related to prior If statement.
What you can do is put the processing statement(s) on the next line after each If-Then and ElseIf-Then statements.
Example,
If memb = "Gold" Then
d = 0.005
ElseIf memb = "Platinum" Then
d = 0.01
ElseIf memb = "Black" Then
d = 0.03
End If
With this in mind, you may want to fix the succeeding If-Then-Else statements in your code. The End If part becomes meaningless if your If-Then-Else is in a single line.
Your code seems to have syntax error and error message tells you that.
Or you did not post all code?
Have a look on MS documentation: https://msdn.microsoft.com/de-de/library/752y8abs.aspx
Do you really stick to the syntax?
Without even having MS OFfice this should (be better readable and) work:
If memb = "Platinum" Then
d = 0.01
ElseIf memb = "Black" Then
d = 0.03
End If
If st >= min Then
cb = st * d
Else
cb = 0
End If
If cb >= thresh Then
MsgBox ("cb is greater than thresh")
End If
tac = st + cb
Range("B5").Value = st
Range("B7").Value = cb
Range("B9").Value = tac
How to make first letter in upper case while pressing tab or space in vb 6.0 ?
My code is as follows
txtFirstName.Text = UCase$(txtFirstName.Text)
but it doesn't change after tab or space
It's just simple just do this in the text box keypress events...
Private sub textbox_keypress(KeyAscii As Integer)
KeyAscii = Asc(UCase(Chr(KeyAscii)))
End Sub
Use the LostFocus event
Private Sub yourTextBox_LostFocus()
With yourTextBox
'first letter in upper case, the rest, untouched.
.Text = UCase(Mid(.Text, 1, 1)) & Mid(.Text, 2, Len(.Text))
End With
End Sub
Apply the same logic to the KeyDown event and check if the pressed key is the space key.
Private Sub yourTextBox_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = 32 Then
With yourTextBox
'first letter in upper case, the rest, untouched.
.Text = UCase(Mid(.Text, 1, 1)) & Mid(.Text, 2, Len(.Text))
.SelStart = Len(.Text) 'put the cursor at the end of the textbox...
End With
End If
End Sub
StrConv Function
Returns a Variant (String) converted as specified.
Syntax
StrConv(string, conversion, LCID)
The StrConv function syntax has these named arguments:
Part Description
string Required. String expression to be converted.
conversion Required. Integer. The sum of values specifying the type of conversion to perform.
LCID Optional. The LocaleID, if different than the system LocaleID. (The system LocaleID is the default.)
Settings
The conversion argument settings are:
Constant Value Description
vbUpperCase 1 Converts the string to uppercase characters.
vbLowerCase 2 Converts the string to lowercase characters.
vbProperCase 3 Converts the first letter of every word in string to uppercase.
AND THERE IS MORE ...
TO GSERGE
$ means nothing when applied to a function name as opposed to a variable name. VBA uses $ AND B as a suffix to denote similar functionality.
VB6 IS VBA the person who said maybe in VB6 but not in VBA. VB6 program host VBA as their programming language. VB6 on it's own are some app objects and the forms package only - no programming language. It's best to think of VB6 as a VBA host like Office.
If you want to proper case see this WORDBASIC Ver 6 code, (which word 2003 helpfully converted to vba).
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
Public Sub MAIN()
Select Case WordBasic.Int(GetModifer)
Case 0
WordBasic.ChangeCase
Case 1
WordBasic.ChangeCase 4
Case 2
WordBasic.ChangeCase 2
Case 3
ProperCase
Case Else
WordBasic.ChangeCase
End Select
End Sub
Private Sub ProperCase()
Dim F
Dim z
Dim a$
Dim P
F = 1
WordBasic.ChangeCase 2
WordBasic.EditBookmark Name:="SerenityChangeCase", SortBy:=0, Add:=1
z = WordBasic.GetSelEndPos()
WordBasic.CharLeft 1
While WordBasic.GetSelEndPos() < z And Not WordBasic.AtEndOfDocument()
WordBasic.SelectCurWord
a$ = WordBasic.[Selection$]()
P = 0
If LCase(a$) = "a" Then
P = 1
ElseIf LCase(a$) = "an" Then
P = 1
ElseIf LCase(a$) = "as" Then
P = 1
ElseIf LCase(a$) = "at" Then
P = 1
ElseIf LCase(a$) = "be" Then
P = 1
ElseIf LCase(a$) = "by" Then
P = 1
ElseIf LCase(a$) = "in" Then
P = 1
ElseIf LCase(a$) = "is" Then
P = 1
ElseIf LCase(a$) = "of" Then
P = 1
ElseIf LCase(a$) = "on" Then
P = 1
ElseIf LCase(a$) = "or" Then
P = 1
ElseIf LCase(a$) = "to" Then
P = 1
ElseIf LCase(a$) = "and" Then
P = 1
ElseIf LCase(a$) = "are" Then
P = 1
ElseIf LCase(a$) = "for" Then
P = 1
ElseIf LCase(a$) = "the" Then
P = 1
ElseIf LCase(a$) = "from" Then
P = 1
ElseIf LCase(a$) = "what" Then
P = 1
ElseIf LCase(a$) = "with" Then
P = 1
End If
If P = 1 And F = 0 Then WordBasic.Insert LCase(a$)
WordBasic.WordRight 1
F = 0
Wend
WordBasic.WW7_EditGoTo Destination:="SerenityChangeCase"
WordBasic.EditBookmark Name:="SerenityChangeCase", SortBy:=0, Delete:=1
End Sub
Private Function GetModifer()
Dim a
Dim B
Dim c
Dim X
a = GetAsyncKeyState(16)
B = GetAsyncKeyState(17)
c = GetAsyncKeyState(18)
X = 0
If a < 0 Then X = X + 1
If B < 0 Then X = X + 2
If c < 0 Then X = X + 4
GetModifer = X
End Function
OK. Yeah txtFirstName is a good indicator of usage here.. So I'd use (sort of) Title Caps And I'd do it on the Validate event.. So
Private Sub txtFirstName_Validate(Cancel As Boolean)
Dim p As Integer ' i doubt we'll use more than 32K for a name....
Dim mName As String
p = 1
' first off lets trim any leading blanks.. assume NOTHING and make sure its all lower case..
mName = LCase(LTrim(txtFirstName))
Do While p > 0 And p <= Len(txtFirstName) ' start with the first non-blank
Mid(mName, p, 1) = UCase(Mid(mName, p, 1))
p = InStr(p, mName, " ")
If p > 0 And p < Len(mName) Then p = p + 1
Loop
Cancel = False
txtFirstName = mName
End Sub
Works every time, and capitalizes each word.. Didn't add any code to to do TRUE title caps but this is close, and short & easy...
I am a total novice with visual basic and teaching myself as I go along. I am building a VB in studio 2008 (I'm obliged to use this version) that logs into a device , transmits log in and password and then transmits commands read from a .txt file using reflections. All of this is working fine. The device executes the command and outputs 1 of 28 possible responses.
I am using select case to evaluate the responses and act accordingly. The device session stops as expected when EXECUTED is seen in the session window, my test data is designed so the first response I get is "EXECUTED", the weird thing is my VB "sees" the EXECUTED message (Case 1) but select case responds as if it has seen FAILED (Case 2), subsequent lines of the test data illicit different cases (5 and 6) but the response is always the next case along. I have tried Case n, case is = n, case "string value" but I get errors.
Here's my code - note that I haven't defined all 28 cases yet but the undefined ones are REM'ed out in my active version. Any ideas or suggestions would be gratefully received!
Option Explicit On
Public Class modCaseSelect
Shared Sub Dev_Responses(ByVal refl)
Dim Result As String
Dim CR = vbCr
Dim Resp As Integer
Dim Dev_Resp(28) As String
Dev_Resp(0) = "RUNNING"
Dev_Resp(1) = "EXECUTED"
Dev_Resp(2) = "FAILED"
Dev_Resp(3) = "SEMANTICS ERROR"
Dev_Resp(4) = "NONEXISTENT"
Dev_Resp(5) = "NOT FOUND"
Dev_Resp(6) = "SPECIAL"
Dev_Resp(7) = "CONFIRM: Y/N"
Dev_Resp(8) = "CONFIRM (Y/N)"
Dev_Resp(9) = "CONFIRM EXECUTION: Y/N"
Dev_Resp(10) = "ALREADY EXECUTED"
Dev_Resp(11) = ""
Dev_Resp(12) = ""
Dev_Resp(13) = ""
Dev_Resp(14) = ""
Dev_Resp(15) = ""
Dev_Resp(16) = ""
Dev_Resp(17) = ""
Dev_Resp(18) = ""
Dev_Resp(19) = ""
Dev_Resp(20) = ""
Dev_Resp(21) = ""
Dev_Resp(23) = ""
Dev_Resp(23) = ""
Dev_Resp(24) = ""
Dev_Resp(25) = ""
Dev_Resp(26) = ""
Dev_Resp(27) = ""
Dev_Resp(28) = "IN PROGRESS"
With refl
Select Case .WaitForStrings(Dev_Resp, "0:4:30") 'checkDev_Resp
Case 0 ' "RUNNING"
Result = Dev_Resp(0)
Resp = MsgBox((Dev_Resp(0) & CR & CR & Continue?"), 17, "Case 0 error")
Case 1 ' "EXECUTED"
Result = Dev_Resp(1)
Resp = MsgBox((Dev_Resp(1) & CR & CR & "Continue?"), 17, "Case 1")
Case 2 ' "FAILED"
Result = Dev_Resp(2)
Resp = MsgBox((Dev_Resp(2) & CR & CR & "Continue?"), 17, "Case 2 error")
Case 3 ' "SEMANTICS ERROR"
Result = Dev_Resp(3)
Resp = MsgBox((Dev_Resp(3) & CR & CR & "Continue?"), 17, "Case 3 error")
Case 4 ' "NONEXISTENT"
Result = Dev_Resp(4)
Resp = MsgBox((Dev_Resp(4) & CR & CR & "Continue?"), 17, "Case 4 error")
Case 5 ' "NOT FOUND"
Result = Dev_Resp(5)
Resp = MsgBox((Dev_Resp(5) & CR & CR & "Continue?"), 17, "Case 5 error")
Case 6 ' "SPECIAL"
Result = Dev_Resp(6)
Resp = MsgBox((Dev_Resp(6) & CR & CR & "Continue?"), 17, "Case 6 error")
Case 7 ' "CONFIRM: Y/N"
Result = Dev_Resp(7)
.Transmit("Y" & CR)
Case 8 ' "CONFIRM (Y/N)"
Result = Dev_Resp(8)
.Transmit("Y" & CR)
Case 9 ' "CONFIRM EXECUTION: Y/N"
Result = Dev_Resp(9)
.Transmit("Y" & CR)
Case 10 ' "ALREADY EXECUTED"
Result = Dev_Resp(10)
Resp = MsgBox((Dev_Resp(10) & CR & CR & "Continue?"), 17, "Case 10 error")
Case 11 ' ""
Result = Dev_Resp(11)
Case 12 ' ""
Result = Dev_Resp(12)
Case 13 ' ""
Result = Dev_Resp(13)
Case 14 ' ""
Result = Dev_Resp(14)
Case 15 ' ""
Result = Dev_Resp(15)
Case 16 ' ""
Result = Dev_Resp(16)
Case 17 ' ""
Result = Dev_Resp(17)
Case 18 ' ""
Result = Dev_Resp(18)
Case 19 ' ""
Result = Dev_Resp(19)
Case 20 ' ""
Result = Dev_Resp(20)
Case 21 ' ""
Result = Dev_Resp(21)
Case 22 ' ""
Result = Dev_Resp(22)
Case 23 ' ""
Result = Dev_Resp(23)
Case 24 ' ""
Result = Dev_Resp(24)
Case 25 ' ""
Result = Dev_Resp(25)
Case 26 ' ""
Result = Dev_Resp(26)
Case 27 ' ""
Result = Dev_Resp(27)
Case 28 ' "IN PROGRESS"
Result = Dev_Resp(28)
Resp = MsgBox((Dev_Resp(28) & CR & CR & "Continue?"), 17, "Case 28 error")
Case Else
End Select
End With
End Sub
End Class
You are missing a double quote " in your first Case. Try changing it to this:
Case 0 ' "RUNNING"
Result = Dev_Resp(0)
Resp = MsgBox((Dev_Resp(0) & CR & CR & "Continue?"), 17, "Case 0 error")
Notice I've added the double quote before "Continue?".
Get rid of the With statement. Create and assign a holder variable and use that with the select statement. Doing so will allow you to see what is actually getting passed into the select statement by setting a stop point in the debugger.
Dim temp_resp as integer = refl.WaitForStrings(Dev_Resp, "0:4:30")
Select Case temp_resp
'the case statements here.
End Select
Reflections WaitForStrings uses a zero-based array parameter, but it returns a 1-based index of strings. Waitforstrings sees array entry zero as the first valid entry so the first select case (Case = 1) corresponds to array entry 0.
I have an SQL query that populates a DataGridView through a DataTable:
SELECT top 100 a.Ordnum, oldBFE, newBFE, oldCBRA, newCBRA, oldLOMC, newLOMC, oldfld, newfld FROM
(SELECT Ordnum, PrpBFE as oldBFE, CBRADte as oldCBRA, LOMCDte as oldLOMC, FldZne AS oldfld
FROM [TOD].[dbo].[Orders] with (NOLOCK) WHERE RecRevDesc = '1 - Order Clone') a
JOIN
(SELECT Ordnum, PrpBFE as newBFE CBRADte as newCBRA, LOMCDte as newLOMC, FldZne AS newfld
FROM [TOD].[dbo].[Orders] with (NOLOCK) WHERE RecRevDesc = '2 Determination Completed-Workflow') b
ON a.Ordnum = b.Ordnum
If the value of certain pairs of cells are not equal, I need both cells to have a red forecolor. Right now, I am firing this through the cellformatting event:
For i As Integer = 0 To Me.gridCompare.RowCount - 1
If Me.gridCompare.Rows(i).Cells(1).ToString <> Me.gridCompare.Rows(i).Cells(2).ToString Then
Me.gridCompare.Rows(i).Cells(1).Style.ForeColor = Color.Red
Me.gridCompare.Rows(i).Cells(2).Style.ForeColor = Color.Red
ElseIf Me.gridCompare.Rows(i).Cells(3).ToString <> Me.gridCompare.Rows(i).Cells(4).ToString Then
Me.gridCompare.Rows(i).Cells(3).Style.ForeColor = Color.Red
Me.gridCompare.Rows(i).Cells(4).Style.ForeColor = Color.Red
ElseIf Me.gridCompare.Rows(i).Cells(5).ToString <> Me.gridCompare.Rows(i).Cells(6).ToString Then
Me.gridCompare.Rows(i).Cells(5).Style.ForeColor = Color.Red
Me.gridCompare.Rows(i).Cells(6).Style.ForeColor = Color.Red
ElseIf Me.gridCompare.Rows(i).Cells(7).ToString <> Me.gridCompare.Rows(i).Cells(8).ToString Then
Me.gridCompare.Rows(i).Cells(7).Style.ForeColor = Color.Red
Me.gridCompare.Rows(i).Cells(8).Style.ForeColor = Color.Red
End If
Next
However, only cells 1 and 2 have the correct formatting. What am I doing wrong? The order of the columns does not matter. I have tried individual IF statements as well.
You can't use the ElseIf branch since that will prevent testing the other pairs. Put each test in it's own IF-EndIf. You also need to test the Value property of the Cell:
If Me.gridCompare.Rows(i).Cells(1).Value.ToString <> _
Me.gridCompare.Rows(i).Cells(2).Value.ToString Then
'etc
End If
If Me.gridCompare.Rows(i).Cells(3).Value.ToString <> _
Me.gridCompare.Rows(i).Cells(4).Value.ToString Then
'etc
End If
Also, make sure those cells aren't null (or nothing) or else it will throw an exception.
So what the issue is, i have 2 for loops one nested within another. The outer loop calling a procedure, the inner loop setting a attribute for the procedure to use. The problem is that the procedure is that I wan't to exit the loop use the pos <-- attribute call the procedure and re-enter the inner loop. At the minute the pos is only being set once because all the conditions are true within the inner loop meaning that its being replaced each time. I want to be able to set the pos exit the inner loop, call the procedure and re-enter the inner loop and set it pos to a different value? any help would be great!! here is the code
For Each val As String In vals
If creditPoints = "20" And semester = "1" And year = "Year 1" Then
For Each position In MyPosList
If position.strLabel = "a1" And available(0) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(0) = blnavailable
ElseIf position.strLabel = "b1" And available(1) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(1) = blnavailable
Next
shortfat(semester, pos, creditPoints, title, year, modStatus, count)
End If
next
Are you just looking to break out of the inner loop when one of those conditions are met? If so, that's what the Exit keyword is for. You really should also set a flag to sanity check yourself, too.
''//Flag so that we know if we actually found a position
Dim FoundPosition as Boolean
For Each val As String In vals
''//Reset the flag and assume that are conditions are met
FoundPosition = False
If creditPoints = "20" And semester = "1" And year = "Year 1" Then
For Each position In MyPosList
If position.strLabel = "a1" And available(0) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(0) = blnavailable
''//Flag that our conditions are met
FoundPosition = True
''//Exit from the inner loop
Exit For
ElseIf position.strLabel = "b1" And available(1) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(1) = blnavailable
''//Flag that our conditions are met
FoundPosition = True
''//Exit from the inner loop
Exit For
End If
Next
''//Sanity check to ensure that our conditions are met
If FoundPosition Then
shortfat(semester, pos, creditPoints, title, year, modStatus, count)
Else
''//Do something here, either Throw an error or safely handle this case otherwise
End If
End If
Next
"I want to be able to set the pos exit the inner loop, call the
procedure and re-enter the inner loop and set it pos to a different
value?"
Things like that are better served with a WHILE loop than a FOR loop.
Just a stab in the dark here, but it sounds like you want to be able to see if shortfat is producing a favorable value. And if it does not, you want it to recompute pos. The first thing I'd do, is alter shortfat to return some kind of value...for my example, I'll have it return a boolean.
Dim blnDidThisDoWhatIWant As Boolean
For Each val As String In vals
If creditPoints = "20" And semester = "1" And Year() = "Year 1" Then
blnDidThisDoWhatIWant = False
While blnDidThisDoWhatIWant = False
For Each position In MyPosList
If position.strLabel = "a1" And available(0) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(0) = blnavailable
ElseIf position.strLabel = "b1" And available(1) <> "False" Then
pos = position.strX & " " & position.strY
count += 1
available(1) = blnavailable
End If
Next
blnDidThisDoWhatIWant = shortfat(semester, pos, creditPoints, title, Year, modStatus, count)
End While
End If
Next
This will allow you to re-enter the inner loop. The problem is that it'll be infinite unless pos is computed differently (which I don't see how it can). So that's something you'll have to work out on your own. Hope this helps point you in the right direction.