I figured I'd ask this here before I go back to other sites.

I'm trying to dynamically create a set of stopwatches and buttons. Each stopwatch will be controlled by a button which is also dynamically created.

However, each time I code it, I always ended wiring both buttons to control the same timer.

Can anyone help?

Recommended Answers

All 12 Replies

sorry but i cant get your point , can you please tell me that you want to create buttons and stopwatches dynamically , but how to get the number of buttons and stopwatches you have to create ? . sorry for my bad english , but rephrase your question so that i can help you

For indexCounter As Integer = 1 To TotalParticipants Step 1

        participantClock = New Label
        participantClock.Size = New Size(100, 20)
        participantClock.Name = "participantClock" & indexCounter
        participantClock.Location = New Point(139, (5 + ((indexCounter - 1) * 26)))
        participantClock.BorderStyle = BorderStyle.Fixed3D
        participantClock.TextAlign = ContentAlignment.MiddleRight
        CenterPanel.Controls.Add(participantClock)

        participantStop = New Button
        participantStop.Size = New Size(58, 20)
        participantStop.Location = New Point(245, (5 + ((indexCounter - 1) * 26)))
        participantStop.BackColor = Color.Red
        participantStop.ForeColor = Color.White
        participantStop.Font = New Font(participantStop.Font, FontStyle.Bold)
        participantStop.Text = "Stop"
        CenterPanel.Controls.Add(participantStop)

        participantTimer = New Timer
        participantTimer.Start()
        participantTimer.Enabled = True
        participantTimer.Interval = 1

        participantStopwatch = New Stopwatch
        participantStopwatch.Start()
Next

The too long;didn't read version.

Essentially I'm creating a timer, label, stopwatch.

The label will display the stopwatch's elapsed result. But everytime I try to do this, I create a lot of buttons but only one label is updated and all of the buttons control that same (one) timer.

So far I was given the following to add on to the loop:

participantTimer.Tag = participantStopwatch
participantStopwatch.Tag = participantClock 
AddHandler participantTimer.Tick, AddressOf Timer_Tick

But Stopwatches cannot have a Tag component according to VB.

Private Sub Timer_Tick(sender As Object, args As EventArgs)
    Dim myTimer as Timer
    Dim myStopwatch as Stopwatch
    Dim myLabel as Label

    ' Cast to get the Timer object
    If Not typeof sender Is Timer Then Exit Sub
    myTimer = DirectCast(sender, Timer)

    ' Cast to get the Stopwatch object
    If Not typeof myTimer.Tag Is Stopwatch Then Exit Sub
    myStopwatch = DirectCast(myTimer.Tag, Stopwatch)

    ' Cast to get the Label object.
    If Not typeof myStopwatch.Tag is Label Then Exit Sub
    myLabel = DirectCast(myStopwatch.Tag, Label)

    ' Now we can finally update the correct Label from the Stopwatch.
    myLabel.Text = myStopwatch.Value
End Sub

>>But Stopwatches cannot have a Tag component according to VB.
Why not create a Array that stores something similar to a .Tag for the StopWatches and ReDim the Array each time you create them?

>>But Stopwatches cannot have a Tag component according to VB.
Why not create a Array that stores something similar to a .Tag for the StopWatches and ReDim the Array each time you create them?

Can you let me see the code or psuedo code so I can guess at how to start on this?

I had a chance to play w/this "stopwatch" thread and got this.

Public Class Form1
    Private lParticipantClock As Label, btnParticipantStop As Button, tmrParticipantTimer As Timer
    Private iTotalParticipants As Integer

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        iTotalParticipants = 5
        createStopWatches(iTotalParticipants)
    End Sub

    Private Sub createStopWatches(ByVal TotalParticipants As Integer)
        For indexCounter As Integer = 1 To TotalParticipants Step 1

            lParticipantClock = New Label : With lParticipantClock
                .Name = "participantClock" & indexCounter
                .Size = New Size(100, 20) : .Location = New Point(139, (5 + ((indexCounter - 1) * 26)))
                .BorderStyle = BorderStyle.Fixed3D : .TextAlign = ContentAlignment.MiddleRight
            End With : CenterPanel.Controls.Add(lParticipantClock)

            btnParticipantStop = New Button : With btnParticipantStop
                .Name = "ParticipantStop" & indexCounter
                .Size = New Size(58, 20) : .Location = New Point(245, (5 + ((indexCounter - 1) * 26))) : .Cursor = Cursors.Hand
                .BackColor = Color.Red : .ForeColor = Color.White : .Font = New Font(.Font, FontStyle.Bold) : .Text = "Stop"
                AddHandler .Click, AddressOf _ParticipantButtons_Click
            End With : CenterPanel.Controls.Add(btnParticipantStop)

            tmrParticipantTimer = New Timer : With tmrParticipantTimer
                AddHandler .Tick, AddressOf _ParticipantTimers_Tick
                .Interval = 1 : .Start()
            End With
        Next
    End Sub

    Private Sub _ParticipantButtons_Click(sender As System.Object, e As System.EventArgs)
        CType(sender, Button).Text = "done"
    End Sub
    Private Sub _ParticipantTimers_Tick(sender As System.Object, e As System.EventArgs)
        Static iCounter As Integer = -1
        iCounter += 1
        For i As Integer = 1 To iTotalParticipants
            If Not CType(CenterPanel.Controls("ParticipantStop" & i.ToString), Button).Text = "done" Then
                CType(CenterPanel.Controls("participantClock" & i.ToString), Label).Text = iCounter.ToString("00:00:00")
            End If
        Next
    End Sub
End Class

Could Not use StopWatch.Value for some odd reason.

Regarding your recent post, see if this helps.

Public Class Form1
    Private iTotalParticipants As Integer
    Private arTags() As Boolean

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        createStopWatches(5)
    End Sub

    Private Sub createStopWatches(ByVal TotalParticipants As Integer)
        ReDim arTags(TotalParticipants)
        For indexCounter As Integer = 1 To TotalParticipants Step 1
            arTags(indexCounter) = True '// set to true if needed.
            '// all other code here to add.Controls.
        Next
        '// FOR.TESTING
        arTags(1) = False
        MsgBox(arTags(1))
    End Sub
End Class

]edit[ Note: If using my previously posted code, you probably do not have to create a Timer for each participant, just use a single Timer to run the For/Next loop within it's .Tick event.

commented: This is EXACTLY what I was aiming for :). Now I just need to learn what the syntax does as I haven't seen it before. +2

Could Not use StopWatch.Value for some odd reason.

It's because Stopwatches don't return .Values but rather TimeSpans. To get the value you'd have to use something like this:

Private Sub TotalTimer_Tick(sender As System.Object, e As System.EventArgs) Handles TotalTimer.Tick
        Dim elapsed As TimeSpan = Me.matchStopwatch.Elapsed
            MatchClockLbl.Text = String.Format("{0:00}:{1:00}:{2:00}.{3:0}", _
                                           Math.Floor(elapsed.TotalHours), _
                                           elapsed.Minutes, _
                                           elapsed.Seconds, _
                                           Math.Floor((elapsed.Milliseconds / 100)))
    End Sub

EDIT: WOW. I just ran your code posted up in the forum post before this one. THANK YOU SIR! This is exactly what I was going for. Would you mind telling me what exactly the lines of code do, I haven't seen that kind of syntax before.

commented: .thanks for info.:) +12

Okay. Now here's the last thing that I need to do.

There is one additional button that will exist on the form.

The button will add one additional row of timers to the form. So far I managed to manipulate the code given to me to actually add the row, but the timer is still continuing off the last added timer.

How can I reset that timer to 0 and add it to the form.

After this I think the program will be done. (Save for exporting all the times.)

EDIT: And evidently I now have the same problem I originally had... Whenever I add a row, it stops the last one and continues the timer on the following row. :/

Post your current.code, I'll see what I can do from there.
[edit]
>>Would you mind telling me what exactly the lines of code do, I haven't seen that kind of syntax before.
If not same code as mine previously posted, I'll comment the previously posted one, otherwise I'll comment your current.code.:)
+= glad I could help.

Here you go, I'll post up the full program code as I have it.:

Public Class MainFrm

    Public TotalParticipants As Integer ' The total number of participants, will be set via an options form.
    Private participantLbl As Label ' A label which will hold the ordered number.
    Private participantName As TextBox ' A blank textbox to allow the user to name the participant
    Private participantClock As Label ' This is a label which will display the stopwatch
    Private btnParticipantStop As Button ' A button used to the stop the timer on the participant.
    Private participantContinue As Button ' A button used to continue the timer when accidentally stopped.
    Private participantTimer As Timer ' A timer to continuously update the labels on pulses.

    ' The options
    Public numEntrants As Integer = 30 ' The maximum number of participants, set at 30 by default.
    Public startingEntrants As Integer = 2 ' The number of timers to start simultaneously., set a 2 by default
    Public entryTimer As Integer = 90 ' The timer to seperate and space the entries. Set to 90 by default
    Public addAuto As Boolean = False ' A checkbox to determine whether or not to automatically add a participant.

    Dim counterTimer As Integer ' A simple holder to count down the entryTimer.

    Private participantStopwatch As New Stopwatch
    Private matchStopwatch As New Stopwatch
    Private Sub AboutToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles AboutToolStripMenuItem.Click
        About.ShowDialog(Me)
    End Sub
    Private Sub ExitToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles ExitToolStripMenuItem.Click
        If MessageBox.Show("All current data will be lost! Are you sure?", "Exit", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) = Windows.Forms.DialogResult.OK Then
            Me.Close()
        End If

    End Sub
    Private Sub AddPlayerBtn_Click(sender As System.Object, e As System.EventArgs) Handles AddPlayerBtn.Click
        ' Adjust our counter.
        TotalParticipants += 1
        TotalParicipantLbl.Text = TotalParticipants




        If TotalParticipants = numEntrants Then
            AddPlayerBtn.Visible = False
            NoMoreEntrantsLbl.Visible = True
            EndButton.Visible = True
            CountDown.Enabled = False
            CountDown.Stop()

            EntrantDueClock.Text = ":" & String.Format("{0:00}", 0)
        End If

    End Sub
    Private Sub StartButton_Click(sender As System.Object, e As System.EventArgs) Handles StartButton.Click
        ' The Start Match Button was clicked, hide Start Button and turn it into End Match
        ' Also, hide the warning, show the add player button, show the total counters.
        StartButton.Visible = False
        WarningLbl.Visible = False
        AddPlayerBtn.Visible = True
        EnteredLbl.Visible = True
        TotalParicipantLbl.Visible = True
        MaxLabel.Visible = True
        MaxNumberLbl.Visible = True


        ' Set the Countdown Timer to be Equal to the Max Counter.
        counterTimer = entryTimer

        EntrantDueClock.Text = ":" & String.Format("{00}", counterTimer)
        CountDown.Start()


        'Disable the options windows
        OptionsScreen.NumEntrants.Enabled = False
        OptionsScreen.StartingNo.Enabled = False
        OptionsScreen.EntryTimer.Enabled = False


        ' Add x number of rows to the sheet, where x equals the number given in StartingNo
        TotalParticipants = startingEntrants

        ' Set our labels on the form
        MaxNumberLbl.Text = numEntrants
        TotalParicipantLbl.Text = TotalParticipants

        ' Continue to Do this until We hit our target
        ' Create the row (label, textfield, box) and start all timers (Countdown, Match Timer, Participant Timer)
        createInitialStopWatches(TotalParticipants)


        ' Start the Match Timer (a count up timer)
        TotalTimer.Enabled = True
        TotalTimer.Start()
        matchStopwatch.Start()

        participantStopwatch.Start()

    End Sub

    Private Sub EndButton_Click(sender As System.Object, e As System.EventArgs) Handles EndButton.Click
        ' The Stop Event button will stop all active timers. (It's the end of the match.)
        TotalTimer.Enabled = False
        EndButton.Visible = False
        TotalTimer.Stop()
        matchStopwatch.Stop()
        participantStopwatch.Stop()

    End Sub

    Private Sub OptionsToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles OptionsToolStripMenuItem.Click
        OptionsScreen.ShowDialog(Me)
    End Sub

    Private Sub ReadMeToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles ReadMeToolStripMenuItem.Click
        ' Call the Read Me File
    End Sub


    Private Sub TotalTimer_Tick(sender As System.Object, e As System.EventArgs) Handles TotalTimer.Tick
        Dim elapsed As TimeSpan = Me.matchStopwatch.Elapsed
        MatchClockLbl.Text = String.Format("{0:00}:{1:00}:{2:00}.{3:0}", _
        Math.Floor(elapsed.TotalHours), _
        elapsed.Minutes, _
        elapsed.Seconds, _
        Math.Floor((elapsed.Milliseconds / 100)))
    End Sub
    Private Sub CountDown_Tick(sender As System.Object, e As System.EventArgs) Handles CountDown.Tick

        counterTimer -= 1
        If counterTimer = -1 Then
            EntrantDueClock.Text = ":" & String.Format("{0:00}", 0)
        ElseIf counterTimer = -2 Then

            EntrantDueClock.Text = ":" & String.Format("{0:00}", 0)


            If addAuto = True And TotalParticipants <> numEntrants Then
                ' The timer has expired, auto add is enabled, and there is still someone to enter... Add a new entrant.

                TotalParticipants += 1
                TotalParicipantLbl.Text = TotalParticipants


                counterTimer = entryTimer
            ElseIf addAuto = False Then
                CountDown.Enabled = False
                CountDown.Stop()
                ResetTmrBtn.Visible = True
            End If

        Else
            EntrantDueClock.Text = ":" & String.Format("{0:00}", counterTimer)
        End If

    End Sub
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles ResetTmrBtn.Click
        counterTimer = entryTimer
        EntrantDueClock.Text = ":" & String.Format("{0:00}", counterTimer)
        ResetTmrBtn.Visible = False
        CountDown.Enabled = True
        CountDown.Start()

    End Sub
    Private Sub createInitialStopWatches(ByVal StartingParticipants As Integer)
        For indexCounter As Integer = 1 To StartingParticipants Step 1

            participantClock = New Label : With participantClock
                .Name = "participantClock" & indexCounter
                .Size = New Size(100, 20) : .Location = New Point(139, (5 + ((indexCounter - 1) * 26)))
                .BorderStyle = BorderStyle.Fixed3D : .TextAlign = ContentAlignment.MiddleRight
            End With : CenterPanel.Controls.Add(participantClock)

            btnParticipantStop = New Button : With btnParticipantStop
                .Name = "ParticipantStop" & indexCounter
                .Size = New Size(58, 20) : .Location = New Point(245, (5 + ((indexCounter - 1) * 26))) : .Cursor = Cursors.Hand
                .BackColor = Color.Red : .ForeColor = Color.White : .Font = New Font(.Font, FontStyle.Bold) : .Text = "Stop"
                AddHandler .Click, AddressOf _ParticipantButtons_Click
            End With : CenterPanel.Controls.Add(btnParticipantStop)

            participantTimer = New Timer : With participantTimer
                AddHandler .Tick, AddressOf _ParticipantTimers_Tick
                .Interval = 1 : .Start()
            End With
        Next
    End Sub
    Private Sub _ParticipantButtons_Click(sender As System.Object, e As System.EventArgs)
        CType(sender, Button).Text = "done"
    End Sub
    Private Sub _ParticipantTimers_Tick(sender As System.Object, e As System.EventArgs)
        Static iCounter As Integer = -1
        iCounter += 1
        For i As Integer = 1 To startingEntrants
            If Not CType(CenterPanel.Controls("ParticipantStop" & i.ToString), Button).Text = "done" Then
                CType(CenterPanel.Controls("participantClock" & i.ToString), Label).Text = iCounter.ToString("00:00:00")
            End If
        Next
    End Sub
End Class

Essentially what's supposed to happen is this:

StartButton when clicked will call the function to make the initial timers and run the initial timers. It will also enable the "Add Partcipant" to view.

AddParticipant will add one additional row and start the timer for that one. While also making sure that you haven't hit the maximum. If the maximum is reached, disable Add Participant and enable the stop match button

When the total participants = numEntrants, A stop button will be enabled. The stop button will stop any and ALL timers. Both the participants (the dynamically created ones) AND the total match timer which is currently running.

If anything I can provide the entire solution in a Zip if you'd like. Just PM me your email address.

q.q.(quick.question)
If 2.participants running time of "00:23:45" and you add a new.participant, should the new.participant start w/"00:00:00", or should they start w/"00:23:45"

Disregard my previous post If this takes care of the issue.

Public Class Form1
    Private lClock As Label, btnStop As Button, sw() As Stopwatch
    Private iTotalParticipants As Integer '// keep count of players.
    Private sButtonName As String = "Stop", sLabelName As String = "Clock", sButtonDone As String = "Done"
    Private pnMain As Panel

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        pnMain = Panel1 '// Take control of Panel.
        With Button1 : .Text = ".new" : .Cursor = Cursors.Hand : End With
        With Button2 : .Text = ".add" : .Cursor = Cursors.Hand : End With
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        pnMain.Controls.Clear() '// clear.Panel.
        iTotalParticipants = 0 '// reset players.
        createInitialStopWatches(2) '// start w/2 players.
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        createInitialStopWatches(1) '// a single player.
    End Sub
#Region "-----===-----===-----===-----===-----=== DYNAMIC.CONTROLS ===-----===-----===-----===-----===-----"

    Private Sub createInitialStopWatches(ByVal numberOfParticipantsToAdd As Integer)
        For i As Integer = 1 To numberOfParticipantsToAdd
            iTotalParticipants += 1 '// increase players total.
            addStopWatchControls(iTotalParticipants) '// add new.player's controls.
        Next
    End Sub

    Private Sub addStopWatchControls(ByVal selCtlIndex As Integer)
        ReDim Preserve sw(iTotalParticipants) '// Redim the StopWatch.Array and keep previous stopWatches.
        sw(selCtlIndex) = New Stopwatch '// new stopWatch for new participant.
        sw(selCtlIndex).Start()

        lClock = New Label : With lClock
            .Name = sLabelName & selCtlIndex
            .Size = New Size(100, 20) : .Location = New Point(139, (5 + ((selCtlIndex - 1) * 26)))
            .BorderStyle = BorderStyle.Fixed3D : .TextAlign = ContentAlignment.MiddleRight
        End With : pnMain.Controls.Add(lClock) '// add.Label.

        btnStop = New Button : With btnStop
            .Name = sButtonName & selCtlIndex
            .Size = New Size(58, 20) : .Location = New Point(245, (5 + ((selCtlIndex - 1) * 26))) : .Cursor = Cursors.Hand
            .BackColor = Color.Red : .ForeColor = Color.White : .Font = New Font(.Font, FontStyle.Bold) : .Text = sButtonName
            AddHandler .Click, AddressOf _ParticipantStopButtons_Click '// give the Button an event to handle.
        End With : pnMain.Controls.Add(btnStop) '// add.Button.
    End Sub

    Private Sub _ParticipantStopButtons_Click(sender As System.Object, e As System.EventArgs)
        CType(sender, Button).Text = sButtonDone '// get sender and set .Text.
    End Sub
#End Region

    Private WithEvents tmrMain As New Timer With {.Enabled = True} : Private tsTemp As New TimeSpan
    Private Sub _tmrMain_Tick(sender As System.Object, e As System.EventArgs) Handles tmrMain.Tick
        If Not iTotalParticipants = 0 Then
            For i As Integer = 1 To iTotalParticipants
                If Not sw.Length = 0 Then
                    If Not CType(pnMain.Controls(sButtonName & i.ToString), Button).Text = sButtonDone Then '// check for btn.Text.
                        tsTemp = sw(i).Elapsed : With tsTemp '// set TimeSpan for StopWatch.
                            CType(pnMain.Controls(sLabelName & i.ToString), Label).Text = String.Format("{0:00}:{1:00}:{2:00}.{3:0}", _
                               Math.Floor(.TotalHours), .Minutes, .Seconds, Math.Floor((.Milliseconds / 100))) '// display result.
                        End With
                    End If
                End If
            Next
        End If
    End Sub
End Class
commented: Love It.. Just a bit of tinkering on my end. But thanks! +2

q.q.(quick.question)
If 2.participants running time of "00:23:45" and you add a new.participant, should the new.participant start w/"00:00:00", or should they start w/"00:23:45"

The new entrants will have a timer of 00:00:00 and count up from there, the button that is generated with add on will control only the timer to its left.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.