How would I do something similar to this:
Dim amnt As Integer
For x As Integer = 1 To 6
If amnt[x] = 0 Then
btn[x].Enabled = False
End If
Next x
What I mean is, can I reference a variable by using another variable in the name. For example, if "x" were to be 4, then I want to change the button "btn4" to .Enabled = False, but I also want to be able to change the button that I'm changing properties of. So like
If (variablesName & x) = 0 Then
If x is 4 then it should look like this
If variablesName4 = 0 Then
If you mean evaluating a variable by supplying it's name as a string - then this cannot be done in VBA.
For example:
Dim testVar As Integer
Dim v As String
v = "Var"
testVar = 5
Debug.Print test & v '// error
Debug.Print "test" & v '// prints "testVar" as a string
Debug.Print "testVar" '// prints "testVar" as a string
Debug.Print testVar '// prints "5" <~~ only way it can be done
However, for some controls, and some other items - you can access the parent collection and supply a string value to get the correct index. So something like:
For i = 1 To 10
'// Will set checkboxes 1 to 10 to be checked
myForm.Controls("Checkbox" & i).Checked = True
Next
As it stands - it's too broad a question to give a definitive answer, but depending on the kind of objects you are working with you may be able to access a parent collection in this way.
Related
In my form I have a number of 8 text fields named with consecutive numbers (tbx_MyID1 to tbx_MyID8). I want to loop through all 8 text fields to create new records out of the text fields' values. So I am trying to store the text fields names in a variable and address the text fields by this variable. This only creates an error, saying the object does not exist.
Private Sub btn_Enter_Click()
Dim db As Database
Dim rs As Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset("tbl")
Dim x As Integer
x = 1
While x < 9
Dim y As String
y = "tbx_MyID" & x
rs.AddNew
rs.Fields("ID") = Me!y.Value
x = x+1
Wend
rs.Update
rs.Close
Set rs = Nothing
db.Close
End Sub
Replace rs.Fields("ID") = Me!y.Value
with rs.Fields("ID") = Me.Controls("tbx_MyID" & x)
It will work because the default property of the underlying control type (a text box) is the "Text" property.
There are a lot of ways to reference controls dynamically on a form. It might be clearer to declare a variable for the text box, get a reference to it, and then specifically reference the Text property:
Dim ctl As TextBox
Dim x As Integer
x = 1
While x < 9
ctl = Me.Controls("tbx_MyID" & x)
rs.AddNew
rs.Fields("ID") = ctl.Text
x = x+1
Wend
As noted previously, you need to access the form's Controls property.
Additionally, you probably want to store your text box prefix and the number of text boxes in constants, to make your code more readable.
Finally, even Microsoft suggests you replace While...Wend loops with the Do...Loop construct. So updated code might look something like this:
Option Explicit
Private Const TEXT_BOX_PREFIX As String = "tbx_MyID"
Private Const TEXT_BOX_COUNT As Integer = 8
Private Sub Command18_Click()
Dim x As Integer
Dim txtBox As Access.TextBox
For x = 1 To TEXT_BOX_COUNT
Set txtBox = Me.Controls(TEXT_BOX_PREFIX & x)
Debug.Print txtBox.Value
' put your code to add/update records here.
Next x
End Sub
If you clarify your question to indicate how specifically the text boxes relate to new records, I can update my answer to address that part.
So I have a table that has a list of totals im trying to display on a form, I have 10 totals I need to get from the totals table and display in 10 textboxes on the form.
The 10 textboxes are "A1, A2, A3..." and its using DLookup to find the ID field number.
It seems like its a syntax issue with Me.TEXTX & X1.Value though I'm not sure how else I can type it.
Hope this makes sense. Thanks!
Private Sub UPDATETOTALS()
Dim FORMX As String
FORMX = "GRID"
Dim TEXTX As String
TEXTX = "A"
Dim TABLENAMEx As String, FINDFIELDx As String, GETFIELDx As String
TABLENAMEx = "GRID_TOTALS"
FINDFIELDx = "[ID]="
GETFIELDx = "TODAY"
Dim X1 As Integer
For X1 = 1 To 10
Me.TEXTX & X1.Value = DLookup(GETFIELDx, TABLENAMEx, FINDFIELDx & X1)
Next X1
End Sub
You cannot access an object reference directly using a concatenated string, as such reference is not of string data type.
Instead, you will need to access the object from the relevant collection (in this case, the Controls collection), by supplying the name of the object (as a string) to the Item method of that collection.
Since the Item method is the default method for a collection, the item name can immediately follow the collection as an argument.
For example:
For X1 = 1 To 10
Me.Controls(TEXTX & X1).Value = DLookup(GETFIELDx, TABLENAMEx, FINDFIELDx & X1)
Next X1
I have a userform which contains a number of checkboxes from 1 to 100. I have written some very simple code so that when you submit the form it creates a binary string that represents the state of those 100 checkboxes, where 0 is false and 1 is true. The code to do this is here:
Private Sub BusRulesSubmit_Click()
Dim myBinaryString As String
Dim nm As String
Dim c As Control
For busRuleIdx = 1 To 100
nm = "CheckBox" & busRuleIdx
Set c = Controls(nm)
If c.Value = True Then
myBinaryString = myBinaryString & "1"
Else
myBinaryString = myBinaryString & "0"
End If
Next
msgBox myBinaryString
End Sub
I now want to open this Userform from another form, where I have a similar binary string, and use this string to set the values of the checkboxes to true or false as appropariate. However I am having issues when setting my control. The code is here:
Private Sub populateBusRules()
Dim c As Control
Dim myBRBinary As String
myBRBinary = "000000000011100000000000000000000000000000000000000000000000000000000010000000000000000000000000000"
For busRuleIdx = 1 To 100
nm = "BusinessRules.CheckBox" & busRuleIdx
Set c = Controls(nm)
If Mid(myBRBinary, buRuleIdx - 1, 1) = 1 Then
c.Value = True
Else
c.Value = False
End If
Next
End Sub
When I run the above, I get a runtime error "Could not find the specified object" and when going to debug it highlights this problem where the code states "Set c = Controls(nm)" - and I can see that it is failing in the first round of the loop i.e. where nm = "BusinessRules.CheckBox1"
Interestingly if I run the code "Set c = Controls(BusinessRules.CheckBox1)" I get no such issue.
Any help would be much appreciated.
Thanks,
Paul.
I think the BusinessRules is giving you the issue. In the Controls collection, there is no Control named "BusinessRules.CheckBox1", only one named "CheckBox1" within the BusinessRules.Controls collection. Assuming there aren't other issues mentioned in the comments above (like the form being closed before this is called), then this should fix your issue
Weird problem. Stepping through the code with inspections gives me correct answers. Just running it doesn't.
This program loops through each cell in a column, searching for a regex match. When it finds something, checks in a adjacent column to which group it belongs and keeps a count in a dictonary. Ex: Group3:7, Group5: 2, Group3:8
Just stepping through the code gives me incorrect results at the end, but adding and inspection for each known item in the dictionary does the trick. Using Debug.Print for each Dictionary(key) to check how many items I got in each loop also gives me a good output.
Correct // What really hapens after running the code
Group1:23 // Group1:23
Group3:21 // Group3:22
Group6:2 // Group6:2
Group7:3 // Group7:6
Group9:8 // Group9:8
Group11:1 // Group11:12
Group12:2 // Group12:21
Sub Proce()
Dim regEx As New VBScript_RegExp_55.RegExp
Dim matches
Dim Rango, RangoJulio, RangoAgosto As String
Dim DictContador As New Scripting.Dictionary
Dim j As Integer
Dim conteo As Integer
Dim Especialidad As String
regEx.Pattern = "cop|col"
regEx.Global = False 'True matches all occurances, False matches the first occurance
regEx.IgnoreCase = True
i = 3
conteo = 1
RangoJulio = "L3:L283"
RangoAgosto = "L3:L315"
Julio = Excel.ActiveWorkbook.Sheets("Julio")
Rango = RangoJulio
Julio.Activate
For Each celda In Julio.Range(Rango)
If regEx.Test(celda.Value) Then
Set matches = regEx.Execute(celda.Value)
For Each Match In matches
j = 13 'column M
Especialidad = Julio.Cells(i, j).Value
If (Not DictContador.Exists(Especialidad)) Then
Call DictContador.Add(Especialidad, conteo)
GoTo ContinueLoop
End If
conteo = DictContador(Especialidad)
conteo = CInt(conteo) + 1
DictContador(Especialidad) = conteo
Next
End If
ContinueLoop:
i = i + 1
'Debug.Print DictContador(key1)
'Debug.Print DictContador(key2)
'etc
Next
'Finally, write the results in another sheet.
End Sub
It's like VBA saying "I'm going to dupe you if I got a chance"
Thanks
Seems like your main loop can be reduced to this:
For Each celda In Julio.Range(Rango)
If regEx.Test(celda.Value) Then
Especialidad = celda.EntireRow.Cells(13).Value
'make sure the key exists: set initial count=0
If (Not DictContador.Exists(Especialidad)) Then _
DictContador.Add Especialidad, 0
'increment the count
DictContador(Especialidad) = DictContador(Especialidad) +1
End If
Next
You're getting different results stepping through the code because there's a bug/feature with dictionaries that if you inspect items using the watch or immediate window the items will be created if they don't already exist.
To see this put a break point at the first line under the variable declarations, press F5 to run to the break point, then in the immediate window type set DictContador = new Dictionary so the dictionary is initialised empty and add a watch for DictContador("a"). You will see "a" added as an item in the locals window.
Collections offer an alternative method that don't have this issue, they also show values rather than keys which may be more useful for debugging. On the other hand an Exists method is lacking so you would either need to add on error resume next and test for errors instead or add a custom collection class with an exists method added. There are trade-offs with both approaches.
before I start I want to point out that I tagged this question as VBA because I can't actually make a new tag for Winwrap and I've been told that Winwrap is pretty much the same as VBA.
I'm working on SPSS V19.0 and I'm trying to make a code that will help me identify and assign value labels to all values that don't have a label in the specified variable (or all variables).
The pseudo code below is for the version where it's a single variable (perhaps inputted by a text box or maybe sent via a custom dialogue in the SPSS Stats program (call the .sbs file from the syntax giving it the variable name).
Here is the Pseudo Code:
Sub Main(variable As String)
On Error GoTo bye
'Variable Declaration:
Dim i As Integer, intCount As Integer
Dim strValName As String, strVar As String, strCom As String
Dim varLabels As Variant 'This should be an array of all the value labels in the selected record
Dim objSpssApp As 'No idea what to put here, but I want to select the spss main window.
'Original Idea was to use two loops
'The first loop would fill an array with the value lables and use the index as the value and
'The second loop would check to see which values already had labels and then
'Would ask the user for a value label to apply to each value that didn't.
'loop 1
'For i = 0 To -1
'current = GetObject(variable.valuelist(i)) 'would use this to get the value
'Set varLabels(i) = current
'Next
'Loop for each number in the Value list.
strValName = InputBox("Please specify the variable.")
'Loop for each number in the Value list.
For i = 0 To varLabels-1
If IsEmpty (varLabels(i)) Then
'Find value and ask for the current value label
strVar = InputBox("Please insert Label for value "; varLabels(i);" :","Insert Value Label")
'Apply the response to the required number
strCom = "ADD VALUE LABELS " & strVar & Chr$(39) & intCount & Chr$(39) & Chr$(39) & strValName & Chr$(39) &" ."
'Then the piece of code to execute the Syntax
objSpssApp.ExecuteCommands(strCom, False)
End If
'intCount = intCount + 1 'increase the count so that it shows the correct number
'it's out of the loop so that even filled value labels are counted
'Perhaps this method would be better?
Next
Bye:
End Sub
This is in no way functioning code, it's just basically pseudo code for the process that I want to achieve I'm just looking for some help on it, if you could that would be magic.
Many thanks in advance
Mav
Winwrap and VBA are almost identical with differences that you can find in this post:
http://www.winwrap.com/web/basic/reference/?p=doc_tn0143_technote.htm
I haven't used winwrap, but I'll try to answer with my knowledge from VBA.
Dim varLabels As Variant
You can make an array out of this by saying for example
dim varLabels() as variant 'Dynamically declared array
dim varLabels(10) as variant 'Statically declared array
dim varLabels(1 to 10) as variant 'Array starting from 1 - which I mostly use
dim varLabels(1 to 10, 1 to 3) 'Multidimensional array
Dim objSpssApp As ?
"In theory", you can leave this as a variant type or even do
Dim objSpssApp
Without further declaration, which is basically the same - and it will work because a variant can be anything and will not generate an error. It is good custom though to declare you objects according to an explicit datatype in because the variant type is expensive in terms of memory. You should actually find out about the objects class name, but I cannot give you this. I guess that you should do something like:
set objSpssApp = new <Spss Window>
set objSpssApp = nothing 'In the end to release the object
Code:
'loop 1
For i = 0 To -1
current = GetObject(variable.valuelist(i)) 'would use this to get the value
Set varLabels(i) = current
Next
I don't exactly know why you want to count from 0 to -1 but perhaps it is irrelevant.
To fill an array, you can just do: varLabels(i) = i
The SET statement is used to set objects and you don't need to create an object to create an array. Also note that you did not declare half of the variables used here.
Code:
strVar = InputBox("Please insert Label for value "; varLabels(i);" :","Insert Value Label")
Note that the concatenation operator syntax is &.
This appears to be the same in WinWrap:
http://www.winwrap.com/web/basic/language/?p=doc_operators_oper.htm
But you know this, since you use it in your code.
Code:
'intCount = intCount + 1 'increase the count so that it shows the correct number
'it's out of the loop so that even filled value labels are counted
'Perhaps this method would be better?
I'm not sure if I understand this question, but in theory all loops are valid in any situation, it depends on your preference. For ... Next, Do ... Loop, While ... Wend, in the end they all do basically the same thing. intCount = intCount + 1 seems valid when using it in a loop.
Using Next (for ... next)
When using a counter, always use Next iCounter because it increments the counter.
I hope this reply may be of some use to you!