So I want to have different Variables with the same name, except for the numbers at the end. The number increases over time, since it's in a repeat loop.
set i to 0
repeat 6 times
set i to i + 1
set SampleVar & i to i + 10
end repeat
end run
This Syntax is probably completely wrong but, I hope you understand, what I want to achieve.
As already mentioned in the comments by red_menace:
You cannot dynamically create variables like that, they need to be declared at compile time. The normal way to use collections would be to use a list or record.
This is your script rewritten to use lists:
set SampleList to {}
set i to 0
repeat 6 times
set i to i + 1
set the end of SampleList to i
end repeat
I don't know what the advantages of writing it as a record are but it usually takes longer and I'm not quite as familiar with them as I am with lists.
Related
How can I have different parameters value defined in .ini file for each repeat in omnet using cmdenv? I have repeat value as 4 and trying to have different value of accidentStart and accidentDuration.
You can't. And shouldn't. The whole point of repetition is that all parameters have the same value, just the RNGs are seeded differently. So you get a different sample of the same distribution for every result value.
What you're looking for are iteration variables.
Something like this:
**.accidentStart = ${100, 200, 350}s
This will generate 3 runs without repetition, and 12 runs with repeat=4.
and if you add
**.accidentDuration = ${duration=300, 450, 600..1800 step 600}s
this will multiply the number of runs by another factor of 5.
By default, iteration variables produce a Cartesian product of their respective assigned sets of values. But there are ways to change this, consult the manual for how.
I am currently trying you learn VB6 and came across this issue.
I wanted to loop through a for loop and adding a number to a control name.
Dim I As Integer
For I = 1 To 5
S = CStr(I)
If TextS.Text = "" Then
LabelS.ForeColor = &HFF&
Else
LabelS.ForeColor = &H80000012
End If
Next I
This S needs to be added to Text and Label so the colour will be changed without needing to use 5 If Else statements
I hope you can help me with this.
From your comment below:
What i mean is this: If Text1.text = "" Then I need this 1 to be replaced with the variable I, so the for loop can loop through my 5 textboxes and the same for my Labels.
You can't do that (look up a variable using an expression to create its name) in VB6. (Edit: While that statement is true, it's not true that you can't look up form controls using a name from an expression. See "alternative" below.)
What you can do is make an array of your textboxes, and then index into that array. The dev env even helps you do that: Open your form in the dev env and click the first textbox. Change its name to the name you want the array to have (perhaps TextBoxes). Then click the next textbox and change its name to the same thing (TextBoxes). The dev env will ask you:
(Don't ask me why I have a VM lying around with VB6 on it...)
Click Yes, and then you can rename your other textboxes TextBoxes to add them to the array. Then do the same for your labels.
Then your code should look like this:
For I = TextBoxes.LBound To TextBoxes.UBound
If TextBoxes(I).Text = "" Then
Labels(I).ForeColor = &HFF&
Else
Labels(I).ForeColor = &H80000012
End If
Next
LBound is the lowest index of the control array, UBound is the highest. (You can't use the standard LBound and Ubound that take the array as an argument, because control arrays aren't quite normal arrays.) Note also that there's no need to put I on the Next line, that hasn't been required since VB4 or VB5. You can, though, if you like being explicit.
Just make sure that you have exactly the same number of TextBoxes as Labels. Alternately, you could create a user control that consisted of a label and a textbox, and then have a control array of your user control.
Alternative: : You can use the Controls array to look up a control using a name resulting from an expression, like this:
For I = 1 To 5
If Me.Controls("Text" & I).Text = "" Then
Me.Controls("Label" & I).ForeColor = &HFF&
Else
Me.Controls("Label" & I).ForeColor = &H80000012
End If
Next
This has the advantage of mapping over to a very similar construct in VB.Net, should you migrate at some point.
Side note:
I am currently trying you learn VB6...
(tl;dr - I'd recommend learning something else instead, VB6 is outdated and the dev env hasn't been supported in years.)
VB6's development environment has been discontinued and unsupported for years (since 2008). The runtime is still (I believe) supported because of the sheer number of apps that use it, although the most recent patch seems to be from 2012. But FWIW, you'd get a better return on your study time learning VB.net or C#.Net (or any of several non-Microsoft languages), rather than VB6...
I have lots of sub routines and functions like these:
Sub LogInfo(Txt)
'Write an entry to the log file
If LogEnableInfo Then Log "Info: " & Txt
End Sub
Or this:
Function GetSettingValue(Key)
'Get the value of a setting or an empty string if the setting is not set
Dim Res
If Settings.Exists(UCase(Key)) Then Res = Settings(UCase(Key)) Else Res = ""
GetSettingValue = Res
End Function
Or this:
Sub DoExp(Exp, ErrTag)
'Execute an HS.Exp with Error handling and Debugging
Err.Clear
On Error Resume Next
HS.Exp Exp
If Err.Number <> 0 Then
LogError "HS.Exp """ & Exp & """ , Tag: " & ErrTag
Err.Clear
ElseIf LogEnablePut Then
Log "Put: HS.Exp """ & Exp & """ , Tag: " & ErrTag
End If
On Error GoTo 0
End Sub
They're really one liners that don't do much, but I use lots of times, so I don't want to type it out every time. I also use recursive functions a lot.
Since speed and memory use is critical to my application, what I would like to know is if the act of calling a function or sub in vbscript has a considerable performance impact? I know that in PHP, this has been cited as a performance issue. Can I just go ahead and create zillions of little nested functions to do everything or should I use them a little more sparingly?
In my experience using functions repeatedly is a bad thing in VBS, in a small test script I wrote I found that using functions were about 5 times slower.
startTime = Timer
x = 0
For i = 0 To 1000000000
x = x + 1
Next
endTime = Timer
WScript.Echo x
WScript.Echo CStr(endTime - startTime)
startTime = Timer
y = 0
For i = 0 To 1000000000
y = fooBooGoo(y)
Next
endTime = Timer
WScript.Echo y
WScript.Echo CStr(endTime - startTime)
Function fooBooGoo(p)
g = p + 1
fooBooGoo = g
End Function
The output I got was:
1000000001
306.6289
1000000001
1554.875
The rule "violate good practice (don't repeat yourself, clean program structure, ...) for speed gains!" is bad.
I doubt that there is even one real life VBScript program that becomes fast enough as soon as you inline functions/subs/methods - if you show me two, I'm willing to discuss using/writing a preprocessor for VBScript that expands macros and adds line numbering to scripts.
If speed is important, you should benchmark early/continously and optimize for speed by choosing better algorithms or better tools (COM, Net, Shell).
If (3) does not help, switch to a better language.
Samples to illustrate what I mean by "better tools" (#3):
using one ADO connection (created once (with late binding in VBScript)) to execute many SQL statements on a folder of .CSVs instead of using a FSO, .Readline loops, Splits, and complex IFs
using one .Net component (ArrayList, StringBuilder, ...) for many operations instead of using ReDim Preserve on native arrays or string concatenation in a loop
shelling out to dir /s /b c:\where\ever\*.vbs instead of a (faulty/inefficient) homegrown/stolen recursive directory walker that looks at all files to filter the .vbs
Functions are used to carry on a specific task or to perform specific operation. Same as in other languages, but in OOP they are usually called "methods", at least when they are attached to a class. It means to be able to work. Function is the process where a machine can work and make things efficient. here's an ex. that is used in a sentence. the machine won't work right. Or what you could say is the function is the ability to work so the mathematical definition would be the ability to solve an equation/problem. Function means working.
So, with regard to using function re-cursive's would be better but overall in object based languages like vbscript, objects should be created and set=nothing later for actually making system consume memory efficiently.
Thanks
G'Day,
I have a question more towards helping me understand on more about how Excel VBA can effectively manage defined ranges that have been declared in one place in order to execute data well. Just wanting to work out which two options (I know so far) is better or not as preferred best practice before working more on this project.
The problem I'm solving is to make a small table containing a number of failures across a set of fictional suppliers, thus the table looks like this (sorry it is in raw form)
"Company Name" "No. of Failures"
"Be Cool Machine" 7
"Coolant Quarters" 5
"Little Water Coolants 3
"Air Movers Systems" 7
"Generals Coolant" 5
"Admire Coolants" 4
My first option (Const String) is this module/formula as follows.
Option Explicit
Public Const CountofFailures As String = "J7:J12"
Sub btnRandom()
' Declaration of variables
Dim c As Range
' Provide a random number for failures across Suppliers
For Each c In ActiveSheet.Range(CountofFailures)
c.Value = Random1to10
Next c
End Sub
Function Random1to10() As Integer
'Ensure we have a different value each time we run this macro
Randomize
' Provide a random number from 1 to 10 (Maximum number of Failures)
Random1to10 = Int(Rnd() * 10 + 1)
End Function
Second option (Defined Name) is this module/formula as follows.
Option Explicit
Sub btnRandom()
' Declaration of variables
Dim c As Range
Dim iLoop As Long
' Provide a random number for Suppliers with Defined Range
For Each c In ActiveWorkbook.Names("CountofFailures").RefersToRange
c.Value = Random1to10
Next c
End Sub
Function Random1to10() As Integer
'Ensure we have a different value each time we run this macro
Randomize
' Provide a random number from 1 to 10 (Maximum number of Failures)
Random1to10 = Int(Rnd() * 10 + 1)
End Function
Any suggestions - I would do a macro timer test later if this helps?
Would there be a third option if I fetch a range listed in a cell as value? I haven't seen a code that does this in practice?
I don't know the performance difference-I suspect const is faster. My general advice is 'don't worry about performance until you have a performance problem'. Otherwise you end up guessing what to spend your optimize time on and it may not be right.
As for named ranges, the benefit is that they move when you insert rows and columns. If you insert a new column at column I your first example needs to be edited and your second example will conitinue to work.
Both of your codes loop through ranges which will be the bottleneck. I suggest you
Use a range name to automatically "locate" your data - ie if you insert/delete rows and columns your reference remains intact. My experience though is that many range names in a file can end up obfuscating what the workbook is doing
Do a single write to this range
code
Sub QuickFill()
Randomize
Range("CountofFailures").Formula = "=Randbetween(1,10)"
Range("CountofFailures").Value = Range("CountofFailures").Value
End Sub
I have found that Named Ranges are slower (presumably because Excel has to do an internal lookup on the Name to find what it refers to), but you are very unlikely to be able to find a significant dofference except in very extreme cases (tens of thousands of names being referenced tens of thousands or hundreds of thousands times).
And as Dick says: the benefits far outweigh the insignificant speed loss.
I'm using QTP 11.0 which uses VBScript for it's "language".
I have the following four lines of code:
For x = 1 to 8
msgbox(x)
update1 = SwfWindow("NextGen File Maintenance").SwfWindow("SIM Library Configuration").SwfObject("spreadCtl").Object.ActiveSheet.GetValue(x,2)
Next
The return values are:
1
3
3
3
3
3
... forever
I can not seem to use the counter variable in a vbscript for loop without it somehow becoming corrupted - no matter what the name of the variable. I have even tried assigning X to another variable and using that in my GetValue statement with no success.
Am I missing something really simple here? No documentation on Google for a vbscript For loop implies any different usage. I found nothing in reference to QTP either.
Thanks,
Jason
This is very strange, I assume that if you remove the second line in the loop and just leave the MsgBox then x is incremented correctly.
Perhaps ActiveSheet.GetValue takes the first parameter by reference and modifies it. You say that you tried using a temporary variable and it didn't work, have you tried something like this?
For x = 1 to 8
tmp = x
update1 = SwfWindow("NextGen File Maintenance").SwfWindow("SIM Library Configuration").SwfObject("spreadCtl").Object.ActiveSheet.GetValue(tmp, 2)
MsgBox("x=" & x & " tmp=" & tmp)
Next
If the problem is that GetValue indeed changes the index you can try using a function that takes the index by value and then use that in the loop.
Public Function GetVal(ByVal index)
GetVal = SwfWindow("NextGen File Maintenance").SwfWindow("SIM Library Configuration").SwfObject("spreadCtl").Object.ActiveSheet.GetValue(index, 2)
End Function