Adding labels dynamically without specifying location in vb.net - vb.net

I am trying to learn VB.net and I have encountered a problem. I am trying to add labels dynamically to a panel/textbox/groupbox. I noticed that while creating a dynamic label, I would have to specify the location property. I was a bit surprised by this - why would I have to manage the exact location of where the new label will be created? Why not have a layout manager which would automatically take care of this? Anyway, I couldn't find a way to do doing this, but I found an example which advocated usage of textbox to add labels dynamically. But, I am only seeing one label being displayed no matter what in the textbox. (when I debugged, I noticed that more labels were added to the controls object, but display did not reflect accordingly)
Here's what it looks like
Here's the code I am using
Private Sub AddTagCombo_SelectedIndexChanged(sender As Object, e As EventArgs) Handles addTagCombo.SelectedIndexChanged
Dim selectedTag = addTagCombo.Text
If Not IsDuplicateTag(selectedTag) Then
Dim label As Label = New Label
label.Text = selectedTag
label.Name = selectedTag
label.AutoSize = True
label.Top = 10
label.Left = 10
tagsBox.Controls.Add(label)
End If
End Sub
How do I add dynamic labels without worrying about the location of where they will be placed inside another container?

Your code looks ok and generates labels successfully. But it puts your new labels above each other as their locations are identical.
All what you need to chabge the location of each new label. For example, increment lebel.Top for each new labels.
Here a suggestion how to to that:
'Add a variable to increment top location
Dim TopFactor As Integer = 1
Private Sub AddTagCombo_SelectedIndexChanged(sender As Object, e As EventArgs) Handles addTagCombo.SelectedIndexChanged
Dim selectedTag = addTagCombo.Text
If Not IsDuplicateTag(selectedTag) Then
Dim label As Label = New Label
label.Text = selectedTag
label.Name = selectedTag
label.AutoSize = True
label.Top = 10 * TopFactor
label.Left = 10
tagsBox.Controls.Add(label)
'Increment TopFactor
TopFactor +=1
End If
End Sub
Now, the first label will be on location (10,10), the second will be on location (20, 10) .. and so on.
Hope this solve your isssue.

Related

Trouble with variables, I am making Yahtzee for a school project and can't get some code to work and am still learning how to code

This is my first question in this community and I'd like some help with a school project I am doing.
I am implementing a turn system where every time you select a method to score a variable called turn increases by one so that the appropriate label is changed to the points you got that turn.
This is an example of the Ones option to score which checks all the dice and adds up all the dice which have the value one, when the Ones button is pressed it should update the current turn with the points gained. At the moment it only updates the first turns score. The second and third images are of the changes I tried making which don't work.
[Ones][1]
[Ones changed][2]
[Ones error][3]
```
Private Sub btnOnes_Click(sender As Object, e As EventArgs) Handles btnOnes.Click
Dim Nums(4) As Integer
Nums(0) = RandomNum1
Nums(1) = RandomNum2
Nums(2) = RandomNum3
Nums(3) = RandomNum4
Nums(4) = RandomNum5
For i = 0 To 4
If Nums(i) = 1 Then
OnesScore += 1
End If
Next
lblTurnValue1.Text = OnesScore
Turn += 1
btnOnes.Enabled = False
End Sub
Private Sub btnOnes_Click(sender As Object, e As EventArgs) Handles btnOnes.Click
Dim Nums(4) As Integer
Nums(0) = RandomNum1
Nums(1) = RandomNum2
Nums(2) = RandomNum3
Nums(3) = RandomNum4
Nums(4) = RandomNum5
For i = 0 To 4
If Nums(i) = 1 Then
OnesScore += 1
End If
Next
lblTurnValue1(Turn).Text = OnesScore
Turn += 1
btnOnes.Enabled = False
End Sub
Another problem I have been having is automatically updating labels as I want to make a Newbie mode for my Yahtzee game which displays the numbers beside each option to score so you know what score you are going to get before you choose.
I can't use the Ones button for clicking to represent the score because it's used for scoring the points and whenever I try double click on the label to show its code in Visual Studio it only updates in game when the person clicks the number to show their score which is not what I desire.
[Ones label][4]
Private Sub lblOnes_Click(sender As Object, e As EventArgs) Handles lblOnes.Click
lblOnes.Text = OnesScore
End Sub
In short I want to learn how to use variables within names of objects to allow for the right one to be chosen and how to update labels automatically instead of having to click them. Any resources you can provide to further my understanding of VB.NET is really helpful.
Thanks.
[1]: https://i.stack.imgur.com/zUQM6.png
[2]: https://i.stack.imgur.com/c5nJe.png
[3]: https://i.stack.imgur.com/Y3gUE.png
[4]: https://i.stack.imgur.com/BnwZ8.png

How to create multiple labels

I'm new to "coding/programming". I'm trying to make a functional program - I call it "a point to pay". It's like those supermarket programs where they register the thing you are going to buy. So i need to create some labels to register products.
The code I have:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click ''When i click the button
If CantidadVer1.Text = 0 Then ''this verifies how many Labels i have created
CantidadVer1.Text = +1 ''this updates the verification
Dim lbl1 As New Label ''this creates the labels
lbl1.Size = New System.Drawing.Size(159, 23)
lbl1.Text = (Product.Text) ''product.text is a TextBox
lbl1.Location = New System.Drawing.Point(12, 80 + 20) '' i add 20 more everytime i create a label
Me.Controls.Add(lbl1)
ElseIf CantidadVer1.Text = 2 Then ''at this point it creates the label but "crashes" (It dosent work anymore)
CantidadVer1.Text = +1
Dim lbl2 As New Label
lbl2.Size = New System.Drawing.Size(159, 23)
lbl2.Text = (Product.Text)
lbl2.Location = New System.Drawing.Point(12, 80 + 40)
Me.Controls.Add(lbl2)
ElseIf CantidadVer1.Text = 2 Then
CantidadVer1.Text = +1
Dim lbl3 As New Label
lbl3.Size = New System.Drawing.Size(159, 23)
lbl3.Text = (Product.Text)
lbl3.Location = New System.Drawing.Point(12, 80 + 60)
Me.Controls.Add(lbl3)
ElseIf CantidadVer1.Text = 3 Then
CantidadVer1.Text = +1
Dim lbl4 As New Label
lbl4.Size = New System.Drawing.Size(159, 23)
lbl4.Text = (Product.Text)
lbl4.Location = New System.Drawing.Point(12, 80 + 80)
Me.Controls.Add(lbl4)
ElseIf CantidadVer1.Text = 4 Then
CantidadVer1.Text = +1
Dim lbl4 As New Label
lbl4.Size = New System.Drawing.Size(159, 23)
lbl4.Text = (Product.Text)
lbl4.Location = New System.Drawing.Point(12, 80 + 100)
Me.Controls.Add(lbl4)
End If
End Sub
So I execute it and then it creates 2 labels and then crashes.
It is supposed to create 5 labels .
Is there an easier way to create multiple labels without making the program crash?
In your code I only see one label created every time. I don't think the code crashes. Remember in an IF block, if the condition is met in the first part, it skips all subsequent ElseIf conditions.
With a little research, you'll see that the best option would be to use a DataGridView instead of a bunch of labels. You could simply add a new row for each item. Lets say you have a datagridview named DGV_Product with 3 textbox columns for product, quantity and price:
Dim price as Double = 1.99
Dim product as String = "Apple"
Dim qty as integer = 3
DGV_Product.Rows.Add(New String() {product, Cstr(qty), CStr(price)})
That adds a row containing "Apple, 3, 1.99"
But if you insist on using labels, This would work better:
1) Set The following variable at a class level.
Dim lbl_pos as integer
2) In your form Load event handler set the value to 20 less than where you want your first label to appear:
lbl_pos = 80 ' gathered from your code
3) Then in your click event handler of the button you increment the new label's position by 20 before adding the new label.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lbl_pos = lbl_pos + 20 'increment the position
Dim lbl as New Label
With lbl
.Text = "Your Text"
.Location = New Point(10,lbl_pos) '(left position, top position)
' And so Forth
End With
me.controls.add(lbl)
End Sub
With this approach you can add as many labels as you like without a bunch of If-ElseIf blocks.
I hope you rethink your approach and go with the DataGridView instead as it's much more practical and you can add as many rows as you like without hassle.
You have an error in your code .. The line
ElseIf CantidadVer1.Text = 2 Then ''at this point it creates the label but "crashes" (It dosent work anymore
should be
ElseIf CantidadVer1.Text = 1 Then ''at this point it creates the label but "crashes" (It dosent work anymore)
If you dont set the value for CantidadVer1 in the begining. Its value = "" not 0. so it will be the bug if you dont put 0 to the CantidadVer1.text
the first if maybe like this
If CantidadVer1.Text = "" OR CantidadVer1.Text = 0 Then
Your PTP is poorly designed. All the answers here are trying to solve your problem by looking based on what you've done.
But your model is kinda based on your what's in your view. For example, have you planned how you will retrieve all the added products ? The history is inside your view : good luck with that.
That's why I suggest to review your design. For example :
Use a List in your code behind to save your data. Your button_click should only do that (with some validations).
Use a repeater in your view. Bind that repeater to your List : and voila. Your repeater will take care of creating all the label corresponding to all the added products.

Accessing buttons names using variables

In visual basic I want to be able to access a button's name using the number stored in a variable.
For example if I have 24 buttons that are all named 'Button' with the numbers 1, 2, 3... 22, 23, 24 after it. If I want to then change the text in the first eight buttons how would I do that.
Here's my example to help show what I mean:
For i = 1 to 8
Button(i).text = "Hello"
Next
The proposed solutions so far will fail if the Buttons are not directly contained by the Form itself. What if they are in a different container? You could simple change "Me" to "Panel1", for instance, but that doesn't help if the Buttons are spread across multiple containers.
To make it work, regardless of the Buttons locations, use the Controls.Find() method with the "searchAllChildren" option:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ctlName As String
Dim matches() As Control
For i As Integer = 1 To 8
ctlName = "Button" & i
matches = Me.Controls.Find(ctlName, True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is Button Then
Dim btn As Button = DirectCast(matches(0), Button)
btn.Text = "Hello #" & i
End If
Next
End Sub
For index As Integer = 1 To 8
CType(Me.Controls("Button" & index.ToString().Trim()),Button).Text = "Hello"
Next
Use LINQ and you're good to go:
Dim yourButtonArray = yourForm.Controls.OfType(of Button).ToArray
' takes all controls whose Type is Button
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
Or
Dim yourButtonArray = yourForm.Controls.Cast(of Control).Where(
Function(b) b.Name.StartsWith("Button")
).ToArray
' takes all controls whose name starts with "Button" regardless of its type
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
In any case, .Take(8) will iterate on the first 8 items stored inside yourButtonArray

Building a collection of buttons and sorting by text

I have a collection of buttons on a panel, I want to be able to build a collection of those buttons and then sort the buttons by the text on the button. However, I am stuck. This is what I have so far, but I can't figure out how to sort.
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim btn1 As Control
Dim btnArray(0 To 3) As Button
btnArray(0) = btnAll
btnArray(1) = btnWine
btnArray(2) = btnBeer
btnArray(3) = btnNonAlcoholic
For Each btn1 In btnArray
Next
End Sub
You can use a simple manual bubble sort:
Dim Changed as Boolean = False
Do
Changed = False
For i = 0 to btnArray.Count - 2
If btnArray(i).Text > btnArray(i+1).Text Then '< > work for strings as well and they check 'position' in the alphabet. So "A" < "B" and so on
'If order is wrong, switch the two buttons
Dim temp as Button = btnArray(i+1)
btnArray(i + 1) = btnArray(i)
btnArray(i) = temp
Changed = True
End If
Next
'Do this until no more switches are necessary
Loop Until Changed = False
This will order your buttons and is reasonably fast for low numbers of buttons. You could use a list and a custom IComparer object as well and simply call List.Sort with the custom comparer.
See here for example implementations of this approach for a similar problem: http://msdn.microsoft.com/en-us/library/cfttsh47%28v=vs.110%29.aspx
Using LINQ:
btnArray = btnArray.OrderBy(Function(btn) btn.Text).ToArray

Display output on the form in VB 2010

I'm designing a windows form. I have output to be displayed on the form it self.
Tried using print, but it is not working.
How do I do that?
I'M NOT PRINTING THE FORM.
ADDED:
I need to display 3 numbers with text string next to each number.
I want to do this in a way that it shows in the form or label in the form without overwriting the previous results.
example:
3 (wrong) 1 (right) 8 (wrong)
2 (wrong) 1 (right) 5 (right)
9 (right) 1 (right) 5 (right)
ADDED:
Thanks for the help everyone. one more question and i think i'm good.
I was thinking of doing something like this inside a loop, problem is I can't add a string and an int together to make a new var:
Xnum1 = Xnum1 + 50
Xnum2 = Xnum1 + ".0F"
Ynum1 = Ynum1 + 50
Ynum2 = Ynum1 + ".0F"
In VB6 you could use the Print statement to draw to the surface of the form. In VB.NET, however, you should be using the Form.CreateGraphics method to create a new Graphics object that can be used to draw to the form's surface. For instance:
Private Sub PrintText(text As String, x As Single, y As Single)
Dim g As Graphics = Me.CreateGraphics()
g.DrawString(text, New Font("Arial", 16), New SolidBrush(Color.Black), New PointF(x, y))
End Sub
That would be the closest equivalent to using the VB6 Print statement like that.
However, I would strongly recommend using a control to display the data. It looks like for the data you need to display, a simple multi-line text box or label would be sufficient. For instance:
Private Sub AppendResult(index As Integer, right As Boolean)
If right Then
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (right)"
Else
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (wrong)"
End If
End Sub
If you want to get more fancy, you could look into using a data grid, a list box, a list view, or even a table layout control instead.
I believe that the most efficient way is to use a tableLayoutPanel with 6 columns. Add in each cell a label showing in the first cell the number, in the second the indicator for that number (right/wrong). Do the same for second and third number.(second number = third and fourth cell, third number =fifth and sixth cell)
For the next set of numbers you can add a new row with with labels in each cell.
I'll add some code to make my answer more professional.
First you add the tableLayoutPanel in your form. You size it as you like (make its width, long enough to handle the data)
You delete the lastRow and then you add columns (you want to have 6 columns). You edit the size of the columns to be Percentage =16.67%
Public Class Form1
Private rowIndex
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i = 0 To 4 Step 2
Dim val As Integer = 3
AddLabels(val, i, 0)
Next
For i = 1 To 5 Step 2
Dim val As String = "right"
AddLabels(val, i, 0)
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
rowIndex = rowIndex + 1
Me.TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Absolute, 30))
Me.TableLayoutPanel1.Height = Me.TableLayoutPanel1.Height + 30
For i = 0 To 4 Step 2
Dim val As Integer = 3 'here you have to put your number
AddLabels(val, i, rowIndex)
Next
For i = 1 To 5 Step 2
Dim val As String = "right" 'here you have to put your indicator
AddLabels(val, i, rowIndex)
Next
End Sub
Private Sub AddLabels(ByVal lblValue As String, ByVal column As Integer, ByVal row As Integer)
Dim lblHeader As New Label
lblHeader.AutoSize = True
lblHeader.Margin = New Padding(0)
lblHeader.BackColor = Color.Transparent
lblHeader.TextAlign = ContentAlignment.MiddleLeft
lblHeader.Dock = DockStyle.None
lblHeader.Text = lblValue
'Put the lblHeader in the right cell
Dim lblHeaderPos As New TableLayoutPanelCellPosition(column, row)
TableLayoutPanel1.SetCellPosition(lblHeader, lblHeaderPos)
TableLayoutPanel1.Controls.Add(lblHeader)
End Sub
Let me know if you facing any problems.
Also if you don't know how many rows you will add, put the tableLyoutPanel inside a panel. Make the panel's property AutoScroll=True and then you can add infinite number of new rows.