Loop Through Specific Labels

parodocs

Member
Joined
Mar 26, 2020
Messages
5
Programming Experience
1-3
Hello,
I have a form with a column of twenty-four labels. The form will also contain other labels. My question is:
How can I loop through the column of labels - and only the column - in sequential order.
The purpose: each labels text represents a time. The options for the time setting will be either standard or military. To write the changes for each label manually is the obvious option, but I'm hoping short and neat is possible, and i can use a loop.
If not - tedium only lasts a minute.
Thank you,
Shawn
 
One option would be to add a Panel to your form and then add the Labels to the Panel. You can then just access every Label on the Panel:
VB.NET:
For Each lbl As Label In myPanel.Controls
Another option would be to name the Labels the same with a numerical suffix:
VB.NET:
For i = 1 To 24
    Dim lbl = DirectCast(Controls($"Label{i}"), Label)
Yet another option would be to set the Tag of each of those Labels and match on that. You could even number the Tags sequentially to force an order if you can't just follow the z-order:
VB.NET:
For Each lbl In Controls.OfType(Of Label)().Where(Function(l) l.Tag IsNot Nothing).OrderBy(Function(l) CInt(l.Tag))
 
Hello,
Thank you for your response.
I wondered if the first would work; had tried the second and failed and haven't heard of the third - I mean, i know what Tags are, just wasn't aware they could be utilized this way.
I wrote a little program to load data into labels using the lines of code you provided. At first it worked; and then I upgraded Visual Studio.

LabelMask holds the standard and military time plus a true/false to test visibility for each of the twenty four labels.
The first times - before the upgrade - the lines of code you offered, plus a few more, loaded the military time into the label. Now it gives me an error. Unfortunately, my experience with VB.net error codes is scant.
VB.NET:
Public Class Form1

    Dim LabelMask(0 To 5, 0 To 3) As String

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        LabelMask(0, 0) = "00:00"
        LabelMask(0, 1) = "12:00 AM"
        LabelMask(0, 2) = "False"
        LabelMask(2, 0) = "01:00"
        LabelMask(2, 1) = "1:00 AM"
        LabelMask(2, 2) = "True"
        LabelMask(3, 0) = "02:00"
        LabelMask(3, 1) = "2:00 AM"
        LabelMask(3, 2) = "True"
        LabelMask(4, 0) = "03:00"
        LabelMask(4, 1) = "3:00 AM"
        LabelMask(4, 2) = "False"
        LabelMask(1, 0) = "04:00"
        LabelMask(1, 1) = "4:00 AM"
        LabelMask(1, 2) = "True"
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim X As Integer

        For X = 0 To 4
            Dim lbl = DirectCast(Controls($"TimeLab{X}"), Label)
            lbl.Text = LabelMask(X, 0)
        Next X
    End Sub

End Class
Wish they had a book with all of these tricks in it.
Anyway, if you can think of why, or have any other input - or anyone else - your help would be most appreciated.

Thank you,
Shawn

P.S.
I also tried this:
VB.NET:
Public Class Form1

    Dim Labs(0 To 2) As String

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Labs(0) = "00:00"
        Labs(1) = "01:00"
        Labs(2) = "02:00"
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim ArrLabs() As Label = {Label1, Label2, Label3} 'Etc...

        For x As Integer = 0 To 2
            ArrLabs(x).Text = Labs(x)
        Next
    End Sub

End Class
and:
now it works. And the next time it will give me two errors and 10 warnings.
Is this normal behaviour for Visual?

Anyway, back to my beer driven contemplation of how best to do this.
Happy eve',
Shawn
 

Attachments

  • Errors.JPG
    Errors.JPG
    35.3 KB · Views: 10
  • Errors.JPG
    Errors.JPG
    100.4 KB · Views: 10
Last edited by a moderator:
The error message tells you exactly what the issue is. You used an invalid index. You need to use the debugger to find out exactly where it happens, exactly what index is being used and exactly what the valid range is at that time.
 
On a different note, don't use 2D arrays like that. Maybe you have been taught that, as it is unfortunate that many beginner courses do teach that because they think that teaching types at that stage is too hard. 2D arrays should only be used as a genuine matrix, e.g. to indicate seats in a grid formation in a classroom. If you're trying to use a 2D array as though each 'row" is a record and each "column" is different data in that record then you're abusing the array. What you ought to do is define a type to represent a record and then create a 1D array or collection of instances of that type. For instance:
VB.NET:
Public Class LabelMask

    Public Property Time As TimeSpan

    Public ReadOnly Property StandardTime As String
        Get
            Return Date.Today.Add(Time).ToString("h:mm tt")
        End Get
    End Property

    Public ReadOnly Property MilitaryTime As String
        Get
            Return Time.ToString("HH\:mm")
        End Get
    End Property

    Public Property IsVisible As Boolean

End Class
Note that the StandardTime property has to create a Date and call ToString on that because the TimeSpan type only represents a time period and not a time of day, so does not support AM/PM formatting. The MilitaryTime property can use TimeSpan formatting without issue. It is better to have a single source of truth for the time and then format that as required, because that makes sure that you can't have the two properties returning values that represent different times.

You can then create an array like so:
VB.NET:
Dim labelMasks = {New LabelMask With {.Time = TimeSpan.Zero, IsVisible = False},
                  New LabelMask With {.Time = TimeSpan.FromHours(4), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(1), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(2), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(3), IsVisible = False}}
You can now loop over that array or index it to get LabelMask objects and get the StandardTime, MilitaryTime and IsVisible properties of those objects.
 
Last edited:
The error message tells you exactly what the issue is. You used an invalid index. You need to use the debugger to find out exactly where it happens, exactly what index is being used and exactly what the valid range is at that time.
Hi, I understand out of bounds and indexes etc . . . The point was, as the code was written, there shouldn't be an error. And then I'll close Visual, reopen it and the error is gone. I don't like random IDE errors.
Thank you, Shawn
 
On a different note, don't use 2D arrays like that. Maybe you have been taught that, as it is unfortunate that many beginner courses do teach that because they think that teaching types at that stage is too hard. 2D arrays should only be used as a genuine matrix, e.g. to indicate seats in a grid formation in a classroom. If you're trying to use a 2D array as though each 'row" is a record and each "column" is different data in that record then you're abusing the array. What you ought to do is define a type to represent a record and then create a 1D array or collection of instances of that type. For instance:
VB.NET:
Public Class LabelMask

    Public Property Time As TimeSpan

    Public ReadOnly Property StandardTime As String
        Get
            Return Date.Today.Add(Time).ToString("h:mm tt")
        End Get
    End Property

    Public ReadOnly Property MilitaryTime As String
        Get
            Return Time.ToString("HH\:mm")
        End Get
    End Property

    Public Property IsVisible As Boolean

End Class
Note that the StandardTime property has to create a Date and call ToString on that because the TimeSpan type only represents a time period and not a time of day, so does not support AM/PM formatting. The MilitaryTime property can use TimeSpan formatting without issue. It is better to have a single source of truth for the time and then format that as required, because that makes sure that you can't have the two properties returning values that represent different times.

You can then create an array like so:
VB.NET:
Dim labelMasks = {New LabelMask With {.Time = TimeSpan.Zero, IsVisible = False},
                  New LabelMask With {.Time = TimeSpan.FromHours(4), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(1), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(2), IsVisible = True},
                  New LabelMask With {.Time = TimeSpan.FromHours(3), IsVisible = False}}
You can now loop over that array or index it to get LabelMask objects and get the StandardTime, MilitaryTime and IsVisible properties of those objects.
Hello again,
I don't need to format anything. A simple string indicating time with an option to switch between standard or military is all I want for that. I do want a simple method to iterate through labels as an array: Label1(1).text= 'time'. That's all I want. I do need to be able to access specific labels and all properties normally available: backcolour, forecolour, text etc . . .
Thank you for your reply; happy healthy day ,
Shawn
 
Hi, I understand out of bounds and indexes etc . . . The point was, as the code was written, there shouldn't be an error. And then I'll close Visual, reopen it and the error is gone. I don't like random IDE errors.
Thank you, Shawn
What you think should or shouldn't be the case is irrelevant. We all think that our code shouldn't have bugs in it or we wouldn't write that code in the first place. Yours does have a bug in it though, so use the debugger to find it. Just reading the code may be enough for the simplest issues but it clearly isn't in this case.
 
Back
Top