Dynamic checkbox events through commandbutton - vba

I am currently programming a sheet which visualizes data sets in graphs. Because the user of this sheet will not need all the graphs, I would like to let them choose the ones needed through a UserForm. Since the amount of data sets is variable, the UserForm will have the same amount of checkboxes as there are datasets.
The Userform code is as follows.
Private Sub UserForm_Initialize()
Dim chkBoxA As MSForms.CheckBox
Dim chkBoxB As MSForms.CheckBox
Dim lblBox As MSForms.Label
Dim cnt As Control
Amount = Sheet4.Range("C4").Value 'Amount of datasets
For i = 1 To Amount
Set lblBox = Me.Controls.Add("Forms.label.1", "Label" & i)
lblBox.Caption = "Set" & i
lblBox.Left = 5
lblBox.Top = 8 + ((i - 1) * 40)
Set chkBoxA = Me.Controls.Add("Forms.CheckBox.1", "A" & i)
chkBoxA.Caption = "Graph a"
chkBoxA.Left = 55
chkBoxA.Top = 5 + ((i - 1) * 40)
Set chkBoxB = Me.Controls.Add("Forms.CheckBox.1", "B" & i)
chkBoxB.Caption = "Graph b"
chkBoxB.Left = 55
chkBoxB.Top = 20 + ((i - 1) * 40)
Next
CommandButton1.Left = 20
CommandButton1.Top = 40 + ((Amount - 1) * 40)
CommandButton1.TabIndex = Amount * 3 + 1
Me.Height = 220
Me.ScrollBars = fmScrollBarsVertical
Me.ScrollWidth = Me.InsideWidth * 9
For Each cnt In Me.Controls
If cnt.Top + cnt.Height > Me.ScrollHeight Then
Me.ScrollHeight = cnt.Top + cnt.Height + 5
End If
Next
End Sub
When the UserForm is filled in (graphs are chosen by clicking on the options), the user will press CommandButton1. An event should then be run to show the correct graph, but for the simplicity I am first testing if a MsgBox will show up. Unfortunately the MsgBox does not show up.
Private Sub CommandButton1_Click()
'Will fix this with a loop
If A1 = True Then
MsgBox ("TestA1")
End If
If B1 = True then
MsgBox ("TestB1")
End If
If A2 = True then
MsgBox ("TestA2")
End If
Unload Me
End Sub
I am stuck on this part. The checkboxes do show up on the UserForm and they are clickable, but the commandbutton only shuts down the sub (Unload Me). I would like to see the MsgBox show up when I select the corresponding option and click the commandbutton. Any help on getting this to work is appreciated!

You are referencing 'A1' in the sub, but that variable does not exitst at compile time, because you add them dynamically. What you need to do is loop the controls, to check the names. Best practice is to put the checkboxes in a frame, to be able to group them.
Add a frame to the userform and name it 'checkboxframe'
And then instead of:
For i = 1 To Amount
Set lblBox = Me.Controls.Add("Forms.label.1", "Label" & i)
lblBox.Caption = "Set" & i
lblBox.Left = 5
lblBox.Top = 8 + ((i - 1) * 40)
Set chkBoxA = Me.Controls.Add("Forms.CheckBox.1", "A" & i)
chkBoxA.Caption = "Graph a"
chkBoxA.Left = 55
chkBoxA.Top = 5 + ((i - 1) * 40)
Set chkBoxB = Me.Controls.Add("Forms.CheckBox.1", "B" & i)
chkBoxB.Caption = "Graph b"
chkBoxB.Left = 55
chkBoxB.Top = 20 + ((i - 1) * 40)
Next
you would need to do:
With Me.checkboxframe
For i = 1 To Amount
Set lblBox = .Controls.Add("Forms.label.1", "Label" & i)
lblBox.Caption = "Set" & i
lblBox.Left = 5
lblBox.Top = 8 + ((i - 1) * 40)
Set chkBoxA = .Controls.Add("Forms.CheckBox.1", "A" & i)
chkBoxA.Caption = "Graph a"
chkBoxA.Left = 55
chkBoxA.Top = 5 + ((i - 1) * 40)
Set chkBoxB = .Controls.Add("Forms.CheckBox.1", "B" & i)
chkBoxB.Caption = "Graph b"
chkBoxB.Left = 55
chkBoxB.Top = 20 + ((i - 1) * 40)
Next
End With
And to add the checkboxes to the frame, use something like:
For Each ctr In UserForm1.frame("checkboxframe").Controls
If TypeName(ctr) = "CheckBox" Then
If ctr.Value = True Then
'do something usefull here
msgbox ctr.name
End If
End If
Next ctr

The reason nothing appears is because there is no object "A1" manually defined as a variable.
To get the value of the box you Dynamically named "A1" you would have to refer to it as such:
If Me.Controls.Item("A1").Value = True then
Hope this helps!

Related

Dynamic buttons in vb.net using for loop

I want to deal with the arrangement of the buttons. for example i have 10 buttons, i want that after 5 buttons the next 5 buttons will go to the nextline.
Here is the code that i have used:
For i = 1 To 10
Dim btn As New Button
btn.Width = 40
btn.Height = 30
btn.TextAlign = ContentAlignment.MiddleCenter
If i.ToString.Length = 1 Then
btn.Text = "B" & "0" & i
Else
btn.Text = "B" & i
End If
btn.Visible = True
btn.Tag = "Button" & i
Panel1.Controls.Add(btn)
If i <= 5 Then
btn.Location = New Point(10 * 1 + ((i - 1) * btn.Width), 10)
Else
btn.Location = New Point(10 * 1 + ((i - 1) * btn.Width), 10 * 1 + ((i - 1) * btn.Height))
End If
i get the wrong positioning of the buttons. kindly help me on this.
i always get this kind of position. ex:
* * * * *
*
*
*
*
*
What i want is this:
* * * * *
* * * * *
additional: How can i do it with backgroundworker...?
Assuming you are using winforms, instead of trying to position your buttons by hand, I would suggest you use a FlowLayoutPanel control instead of a straight up panel. Then you can just add them and let the panel manage their positions.
For i = 1 to 10
Dim btn As New Button
btn.Width = 40
btn.Height = 30
btn.TextAlign = ContentAlignment.MiddleCenter
If i.ToString.Length = 1 Then
btn.Text = "B" & "0" & i
Else
btn.Text = "B" & i
End If
btn.Visible = True
btn.Tag = "Button" & i
FlowLayoutPanel1.Controls.Add(btn)
Next
If you must have 5 per line (assuming your panel is wide enough), you can use SetFlowBreak:
For i = 1 to 10
'.....
FlowLayoutPanel1.Controls.Add(btn)
'Use this line if you must have only 5 buttons per line.
if i Mod 5 = 0 Then FlowLayoutPanel1.SetFlowBreak(btn, true)
Next
Try this:
If i <= 5 Then
btn.Location = New Point(10 * 1 + ((i - 1) * btn.Width), 10)
Else
btn.Location = New Point(10 * 1 + ((i - 6) * btn.Width), 10 + btn.Height)
End If
EDIT:
If you wanted to change the loop so that you wanted to multiple lines of buttons then look at this:
Dim noOfButtonsPerLine As Integer = 5
Dim buttonIndex As Integer = 0
Dim y As Integer = 10
For i = 1 To 15
Dim btn As New Button With {.Height = 40, .Width = 30}
If buttonIndex = noOfButtonsPerLine Then
buttonIndex = 1
y += btn.Height
Else
buttonIndex += 1
End If
btn.TextAlign = ContentAlignment.MiddleCenter
If i.ToString.Length = 1 Then
btn.Text = "B" & "0" & i
Else
btn.Text = "B" & i
End If
btn.Visible = True
btn.Tag = "Button" & i
Panel1.Controls.Add(btn)
btn.Location = New Point(10 * 1 + ((buttonIndex - 1) * btn.Width), y)
Next
Change the variable noofButtonsPerLine to what suits you. I've gone for 5 as per the question but you can change it and it should adapt.

VB - comparing numbers in two labels

I'm doing a school project in Visual Basic (using visual studio 2015) and i'm kinda stuck.
My goal is to create a lottery, where player chooses 6 numbers from checkboxes, then he generates six random numbers (1 - 49) and finally, those two sets should be compared and needed result is the number of correctly guessed numbers.
I have both results (guessed numbers, generated numbers) saved in two different labels.
The checkboxes itself are genereted like this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lev = 20
tt = 0
For j = 1 To 50
tt = tt + 1
n = n + 1
box(j) = New CheckBox
box(j).Name = "box(" & Str(j) & ")"
If n = 11 Then lev = lev + 110 : n = 1 : tt = 1
box(j).Left = lev
box(j).Parent = Me
box(j).Top = tt * 20
box(j).Tag = j
box(j).Text = j
box(j).Visible = True
Next
box(50).Enabled = False
End Sub
First label (guessed numbers) is filled this way (i'm not posting whole code)
For j = 1 To 50
If box(j).Checked = True Then Label9.Text = Label9.Text + " " + box(j).Text
Next
and the second one (generated numbers) like this:
Do
rn = rg.Next(1, 50)
If Not r.Contains(rn) Then
r.Add(rn)
End If
Loop Until r.Count = 6
Label1.Text = r(0).ToString + " " + r(1).ToString + " " + r(2).ToString + " " + r(3).ToString + " " + r(4).ToString + " " + r(5).ToString
any idea how to compare numbers stored in those labels and get the result (number of correctly guessed numbers).
thanks in advance
You can compare numbers in the labels by splitting the Text properties of the labels into arrays of strings and converting them to integer arrays. First though there is a tiny problem with your code that adds the guessed numbers to the label.
For j = 1 To 50
If box(j).Checked = True Then Label9.Text = Label9.Text + " " + box(j).Text
Next
The " " should be moved to the end of the line because at the moment, the label will always start with a space and that messes with the function below. So you should have -
For j = 1 To 50
If box(j).Checked = True Then Label9.Text = Label9.Text + box(j).Text + " "
Next
Ok. The function below splits the two text labels into their own array and loops through the guesses and checks if any number is contained in the generated numbers. It then returns the number of matches.
Private Function ComparePicks() As Integer
Dim numbersMatched As Integer
Dim picks(5) As Integer
Dim generatedNumbers(5) As Integer
For i As Integer = 0 To 5
picks(i) = CInt(Split(Label9.Text, " "c)(i))
Next
For i As Integer = 0 To 5
generatedNumbers(i) = CInt(Split(Label1.Text, " "c)(i))
Next
For i As Integer = 0 To 5
If generatedNumbers.Contains(picks(i)) Then
numbersMatched += 1
End If
Next
Return numbersMatched
End Function

Need to repeat code 30 times

this is my code and I want to re-execute it so that the next column has the exact same code repeated on it. That is, D:28 moves to E:28 and range E:110:I120 moves to F110:J120. I am having trouble finding a loop that does this, can anyone please help. My code is,
Sub Rebuild()
tonnes = Range("D28").Value
If tonnes > 2600000 Then
Range("E110:I120").Select
Selection.Copy
Range("E18:I28").Select
ActiveSheet.Paste
Else:
Range("E18:I28").Interior.Color = xlNone
Range("E18:I18") = ""
Range("E19:I19") = ""
Range("E20:I20") = 0
Range("E21:I21") = 2.4
Range("E22:I22") = "=E21+E20"
Range("E23:I23") = "=24 - E22"
Range("E24:I24") = "=100 * E23 / 24"
Range("E25:I25") = 3000
Range("E26:I26") = "=E25 * E23"
Range("E27:I27") = "=E26"
Range("E28:I28") = "=D28 + 27"
End If
End Sub
Option Explicit
Sub Rebuild()
Dim cumtonnes As Long
'you initially had tonnes as the variable name, but I was not sure if this was a typo or not.
cumtonnes = Range("D28").Value
If cumtonnes > 2600000 Then
Range("E110:I120").Copy Range("F110:J120")
Range("D28").Copy Range("E28")
Else:
Range("E18:I28").Interior.Color = xlNone
Range("E18:I18") = ""
Range("E19:I19") = ""
Range("E20:I20") = 0
Range("E21:I21") = 2.4
Range("E22:I22") = "=E21+E20"
Range("E23:I23") = "=24 - E22"
Range("E24:I24") = "=100 * E23 / 24"
Range("E25:I25") = 3000
Range("E26:I26") = "=E25 * E23"
Range("E27:I27") = "=E26"
Range("E28:I28") = "=D28 + 27"
End If
End Sub
So I adjusted the part that will do the copy and paste of the cells. I did not add in any loop currently as I did not know what you wanted repeated 30 times.

Moving textbox output into a different textbox

I am trying to output text into another text box once the first has 5 entries in it. Example; i give the scores 100,200,300,200,200. Now when I try to enter a new score it should place it in the next textbox, but doesent.
Dim Testint As Integer ' define an Integer for testing
Dim sampleTextBox(3) As TextBox
sampleTextBox(0) = txtPlayer1Scores
sampleTextBox(1) = txtPlayer2Scores
sampleTextBox(2) = txtPlayer3Scores
sampleTextBox(3) = txtPlayer4Scores
Dim sampleLabel(3) As Label
sampleLabel(0) = lblPlayer1Average
sampleLabel(1) = lblPlayer2Average
sampleLabel(2) = lblPlayer3Average
sampleLabel(3) = lblPlayer4Average
scoreArray(textCount, gameNumber - 1) = CInt(txtScoreInput.Text) ' subtracting 1 from the score array
sampleTextBox(textCount).Text &= " Score:" & scoreArray(textCount, gameNumber - 1) & vbCrLf
'output statement
gameNumber = gameNumber + 1 'increment the counter
If gameNumber > MAX_SCORE_LENGTH Then
sampleTextBox(textCount).Focus()
sampleTextBox(textCount).Enabled = False
For i As Integer = 0 To 4 'Add the array values up
scoreTotal += scoreArray(textCount, i)
Next
playerAverage = scoreTotal / MAX_SCORE_LENGTH
sampleLabel(labelCount).Text = playerAverage
' I need the textbox switch here
textCount = textCount + 1
labelCount = labelCount + 1 ' and labels
ElseIf textCount > MAX_PLAYERS Then
'calculate team average
btnEnterScore.Enabled = False
Else
lblEnterScore.Text = "Enter Score for game #" & gameNumber ' 5 scores have not be inputted,
txtScoreInput.Text = "" 'ask for more
txtScoreInput.Focus() 'refocus the input textbox
End If
Fixed it...setting the max length to 15 forces it to move on after 15 digits, it also works when there are less than 15 digits
txtscore1.MaxLength = 15

Visual Basic - variable names auto increment / loop

Is there a way when I want to do this:
textbox1.text = x + i
textbox2.text = x + i
textbox3.text = x + i
To do for example like this?
for l = 0 to 2
textbox(l) = x + i
next
Assuming these controls are inside a userform, do something like:
Private Sub FillTextboxes()
Dim i As Long
Dim x As Long
x = 10
For i = 0 To 2
Me.Controls("textbox" & i + 1).Text = x + i
Next i
End Sub