How to create multiple labels - vb.net

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.

Related

How to dynamicallty create multiple controls at runtime

I am trying to add multiple labels to a userform at runtime
It's for the player names of a board game; and until the game starts the number of players are not known. I have managed to figure out for myself how to use the dynamic array function to create the list of players. I used a For.....Next loop to add the player names. I thought I could do that to add the labels to the form, but it only adds one. Depending on where the new control type is declared, it either adds the first player only, or the last player
This code produces one label only within the groupbox, the last player
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Players_Num As Integer = InputBox("Enter the number of players")
Dim Players(Players_Num) As String
Dim newText As New Label
For i = 0 To Players_Num - 1
Players(i) = InputBox("Enter player name")
Next
'This piece of code was jsut for me to test that I was successfully using a For...Loop
'to add the players names, and will be deleted later on
For x = 0 To Players_Num - 1
MessageBox.Show(Players(x))
Next
For z = 0 To Players_Num - 1
newText.Name = "txt" & Players(z)
newText.Text = Players(z)
newText.Size = New Size(170, 20)
newText.Location = New Point(12 + 5, 12 + 5)
GroupBox1.Controls.Add(newText)
Next
End Sub
End Class
This one places only the first player
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim Players_Num As Integer = InputBox("Enter the number of players")
Dim Players(Players_Num) As String
For i = 0 To Players_Num - 1
Players(i) = InputBox("Enter player name")
Next
'This piece of code was jsut for me to test that I was successfully using a For...Loop
'to add the players names, and will be deleted later on
For x = 0 To Players_Num - 1
MessageBox.Show(Players(x))
Next
For z = 0 To Players_Num - 1
Dim newText As New Label
newText.Name = "txt" & Players(z)
newText.Text = Players(z)
newText.Size = New Size(170, 20)
newText.Location = New Point(12 + 5, 12 + 5)
GroupBox1.Controls.Add(newText)
Next
End Sub
End Class
I've tried this in vs 2015 and 2019 Community
Where is it going wrong?
From the looks of the code, you are correctly creating the controls but their location is the same for all of them, essentially, they are being place one of top of the other, the first is hidden with the second, which is hidden with the third.
The line
newText.Location = New Point(12 + 5, 12 + 5)
needs to be modified to place the labels at different locations.
Perhaps, something like:
newText.Location = New Point(12 + 5, 12 + (z * 25))
This will vertically align the labels with a gap of 25 between them
You are placing them all in the same location
newText.Location = New Point(12 + 5, 12 + 5)
Use your 'z' index to place them at different locations in order to be able to see them
For me it is easier to contain controls in a TableLayoutPanel then add the TLP to what ever control collection, such as a GroupBox This way you can couple a Label with TextBox, for example. Here's an example how you can create controls from a DataTable. In your case you would only need 1 ColumnStyle for labels, I just thought I would show you a good practice for future shortcuts. (I rarely use the designer to place controls)
'Start test data
Dim DtTable As New DataTable
With DtTable
Dim NewDtRow As DataRow = .NewRow
For i As Integer = 0 To 25
Dim DtCol As New DataColumn With {.ColumnName = "Col" & i, .DataType = GetType(String)}
.Columns.Add(DtCol)
NewDtRow(DtCol.ColumnName) = "Test" & i
Next
.Rows.Add(NewDtRow)
End With
'End test data
Dim TLP1 As New TableLayoutPanel With {.Name = "TlpFields"}
With TLP1
.BorderStyle = BorderStyle.Fixed3D
.CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset
.AutoScroll = True
.AutoSize = True
.RowStyles.Clear()
.ColumnStyles.Clear()
.Dock = DockStyle.Fill
.ColumnCount = 2
.ColumnStyles.Add(New ColumnStyle With {.SizeType = SizeType.AutoSize})
End With
For Each DtCol As DataColumn In DtTable.Columns
With TLP1
.RowCount += 1
.RowStyles.Add(New RowStyle With {.SizeType = SizeType.AutoSize})
'create labels
.Controls.Add(New Label With {
.Text = DtCol.ColumnName,
.Anchor = AnchorStyles.Right}, 0, .RowCount)
'create textboxs
Dim TxtBox As New TextBox With {
.Name = "TextBox" & DtCol.ColumnName,
.Size = New Size(170, 20),
.Anchor = AnchorStyles.Left}
'add binding
TxtBox.DataBindings.Add("Text", DtTable, DtCol.ColumnName)
.Controls.Add(TxtBox, 1, .RowCount)
End With
Next
Controls.Add(TLP1)

Dynamic entries from textfiles into FlowLayoutPanel

I'm currently working on a ToDo program, where you can simply add notes. (With the option to set priority and attachment) The Note will be saved as a textfile. Now I want to make an over view of the ToDo's which have to be done. In the end it's supposed to look like a list, one row for each Note, built like this:
TITLE.............................[Attachment Icon]..[Priority Icon]..[CheckBox]
The checkbox should always be on the very right side of the row.
My idea is to add a FlowLayoutPanel to a FlowLayoutPanel for every Note. In the child-FlowLayoutPanel I'll add the controls. My problem is that I have no Idea how to set the positions of the controls. I tried to add a label and use it as a space between the title and the other controls, but it doesn't really work.
Here's the code I currently have:
For Each File In Directory.GetFiles(myPath)
Dim tlp As New FlowLayoutPanel
tlp.BackColor = Color.Gray
tlp.Width = 260
tlp.FlowDirection = FlowDirection.TopDown
Dim lbl As New Label
lbl.AutoSize = True
lbl.Text = getInsert(File, 0)
lbl.Anchor = AnchorStyles.Right
lbl.ForeColor = Color.White
AddHandler lbl.Click, Sub() Me.getInsert(File, 0)
tlp.Height = 40
Dim cbx As New CheckBox
cbx.FlatStyle = FlatStyle.Flat
cbx.Text = ""
cbx.Width = 15
cbx.Height = 30
AddHandler cbx.CheckStateChanged, Sub() Me.deleteEntry(tlp)
Dim space As New Label
space.AutoSize = False
space.Text = ""
space.Height = 30
space.Anchor = AnchorStyles.Right
tlp.Controls.Add(lbl)
tlp.Controls.Add(Space)
tlp.Controls.Add(cbx)
Space.Width = tlp.Width - lbl.Width - cbx.Width - 15
mfp.Controls.Add(tlp)
Next
Here's an example:
todo_example
I hope anyone has a good idea how to solve this problem.
Thanks in advance :)

Adding labels dynamically without specifying location in 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.

Fitting runtime buttons inside a form

I have a number of buttons between 5-20 and it's variable each time the form loads based on the user settings. I am trying to fit all these buttons on my form no matter what the size of the form is. The buttons are generated during runtime. I would like the first button to be 20 points from the top bar (at any size) and the rest of the buttons simply to fit in the form. This is what I have now but I have to maximize the form to view them all and also while I'm expanding the form the space between the buttons decreases and they overlap with each other whereas they should keep a relative distance. Any ideas?
Dim iButtonWidth, iButtonHeight, iVerticalSpace As Integer
If UserButtons.Count > 0 Then
iButtonHeight = Me.Size.Height - (Me.Size.Height * 0.85)
iButtonWidth = Me.Size.Width - (Me.Size.Width * 0.5)
iVerticalSpace = iButtonHeight / 3
For Each btn In UserButtons
btn.Size = New System.Drawing.Size(iButtonWidth, iButtonHeight)
btn.Location = New Point(20, 20 + btn.TabIndex * iVerticalSpace * 3)
Next
End If
Here's a quick example using the TableLayoutPanel to play with:
Public Class Form1
Private UserButtons As New List(Of Button)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Static R As New Random
Dim NumButtons As Integer = R.Next(5, 21) ' "a number of buttons between 5-20 and it's variable each time"
UserButtons.Clear()
For i As Integer = 1 To NumButtons
Dim btn As New Button()
btn.Text = i.ToString("00")
btn.Dock = DockStyle.Fill ' Optional: See how you like it with this on vs. off
UserButtons.Add(btn)
Next
DisplayButtons()
End Sub
Private Sub DisplayButtons()
TableLayoutPanel1.SuspendLayout()
TableLayoutPanel1.Controls.Clear()
TableLayoutPanel1.ColumnStyles.Clear()
TableLayoutPanel1.ColumnCount = 5 ' Fixed Number of Columns
For i As Integer = 1 To TableLayoutPanel1.ColumnCount
TableLayoutPanel1.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
' Variable Number of Rows:
Dim RowsRequired As Integer = ((UserButtons.Count - 1) \ TableLayoutPanel1.ColumnCount) + 1 ' Integer Division
TableLayoutPanel1.RowStyles.Clear()
TableLayoutPanel1.RowCount = RowsRequired
For i As Integer = 1 To TableLayoutPanel1.RowCount
TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
TableLayoutPanel1.Controls.AddRange(UserButtons.ToArray)
TableLayoutPanel1.ResumeLayout()
End Sub
End Class
First of all what kind of container are the buttons in? You should be able to set the container's AutoScroll property to true - then when controls within it spill out of the visible bounds you will get a scroll bar.
Then also what you could do is draw each button in more of a table with a certain number next to each other before dropping down to the next line (instead of just 1 button on each line). If that is an option that works for you then you could get more buttons within the visible space.
I happen to have an example to do the same thing with picture boxes (and text boxes under each picture box). Hope this helps:
Dim point As New Point(0, 0)
'create 11 picture and text boxes-you can make this number the number your user selects.
Dim box(11) As PictureBox
Dim text(11) As TextBox
Dim i As UInt16
For i = 0 To 11 'or whatever your number is
box(i) = New PictureBox
box(i).Width = 250 'your button width
box(i).Height = 170 'your button height
box(i).BorderStyle = BorderStyle.FixedSingle
box(i).Location = point
layoutsPanel.Controls.Add(box(i)) 'my container is a panel
text(i) = New TextBox
text(i).Height = 50
text(i).Width = 250
point.Y += box(i).Height
text(i).Location = (point)
layoutsPanel.Controls.Add(text(i))
point.Y -= box(i).Height 'reset Y for next picture box
'Put 4 picture boxes in a row, then move down to next row
If i Mod 4 = 3 Then
point.X = 0
point.Y += box(i).Height + text(i).Height + 4
Else
point.X += box(i).Width + 4
End If
Next

vb.net layering of controls not working properly

I simply want to add three controls to my form. The first two show up, but the third does not. I do not understand why this behavior is happening. I have tried using .bringToFront(), but I end up with the same results. I also tried using Me.controls.setChildIndex() but that does not help either.
I am at a loss. I must be doing something wrong. Please help.
Thanks.
This is my code:
' Add the label
' ------------------
Dim menu_label As New Label
menu_label.Text = "Menu"
menu_label.Location = New Point(50, 20)
menu_label.Width = 50
menu_label.Font = New Font(main_font, main_font_size, FontStyle.Regular)
menu_label.ForeColor = Color.White
Me.Controls.Add(menu_label)
' create the image
' ---------------
Dim logo As New PictureBox
Dim logo_image As Image
logo_image = My.Resources.logo
logo.Image = logo_image
logo.Width = 30
logo.Height = 30
logo.Left = 5
logo.Top = 0
Me.Controls.Add(logo)
' add a line
' ----------
Dim line As New Panel
line.Height = 1
line.Width = Me.Width
line.BackColor = Color.Red
line.Location = New Point(0, 32)
Me.Controls.Add(line)
' end code
' ---------------------------------
Only the first two items show up no matter which order I put them in. So I either get just the logo and the menu label, or just the logo and the line, or just the line and the menu label. It's nuts!
So I tried:
Me.Controls.SetChildIndex(logo, 0)
Me.Controls.SetChildIndex(menu_label, 1)
Me.Controls.SetChildIndex(line, 2)
Whichever item gets assigned to level 2 never shows up.
I also tested and it worked fine for me. Changed the form backcolor to black so you can see the results better:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
' Add the label
' ------------------
Dim menu_label As New Label
menu_label.Text = "Menu"
menu_label.Location = New Point(50, 20)
menu_label.Width = 50
'menu_label.Font = New Font(main_font, main_font_size, FontStyle.Regular)
menu_label.ForeColor = Color.White
Me.Controls.Add(menu_label)
' create the image
' ---------------
Dim logo As New PictureBox
Dim logo_image As Image
'logo_image = My.Resources.logo
'logo.Image = logo_image
logo.BackColor = Color.Yellow
logo.Width = 30
logo.Height = 30
logo.Left = 5
logo.Top = 0
Me.Controls.Add(logo)
' add a line
' ----------
Dim line As New Panel
line.Height = 1
line.Width = Me.Width
line.BackColor = Color.Red
line.Location = New Point(0, 32)
Me.Controls.Add(line)
Me.BackColor = Color.Black
End Sub
What else is on your form? Perhaps you could post a screenshot?