如何访问动态添加的Label控件?解决System.NullReferenceException报错
VB.NET动态控件计时程序空引用异常解决方法
问题描述
我正在开发一款计时程序,已实现动态添加多个参赛项的功能,但在通过动态添加的Button激活计时器,将计时结果显示到对应动态添加的Label控件时遇到问题。点击按钮触发事件时,程序抛出错误:System.NullReferenceException: 'Object variable or With block variable not set.'
原代码如下:
Public Class Form1 ReadOnly MyForm Dim ss, tt, vv As Integer Dim ss1, tt1, vv1, ww1 As Integer 'Dim NewLab1 Dim CarNum Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim NewBut1 = New Button Dim NewBut2 = New Button Dim NewLab1 = New Label Dim NewLab2 = New Label Dim NewLab3 = New Label Timer3.Enabled = True ' NewBut1() End Sub Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Label3.Text = Format(ss, "00:") & Format(tt, "00:") & Format(vv, "00") vv = vv + 1 If vv > 59 Then vv = 0 tt = tt + 1 End If If tt = 2 Then vv = 0 tt = 0 Label3.Text = "00:00:00" Timer1.Enabled = False MessageBox.Show("time ended") End If End Sub Private Sub Timer3_Tick(sender As Object, e As EventArgs) Handles Timer3.Tick Label2.Text = Format(Now, "hh:mm:ss") End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click CarNum = InputBox("Add Car Number", "Car Number") Dim NewBut1 = New Button Dim NewBut2 = New Button Dim NewLab1 = New Label Dim NewLab2 = New Label Dim NewLab3 = New Label With NewBut1 .BackColor = Color.Red .ForeColor = Color.White .Text = "Car " & CarNum & " Pit IN" .Location = New Point(12, 200) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded ", 16, FontStyle.Bold) AddHandler NewBut1.Click, AddressOf NewBut1_Click End With With NewBut2 .BackColor = Color.Lime .ForeColor = Color.Black .Text = "Car " & CarNum & " Pit OUT" .Location = New Point(225, 200) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) End With With NewLab1 .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(537, 200) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "Pit Stop Timer" End With With NewLab2 .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(748, 200) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "Stint Timer" End With With NewLab3 .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(953, 200) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "Timer 3" End With Controls.Add(NewBut1) Controls.Add(NewBut2) Controls.Add(NewLab1) Controls.Add(NewLab2) Controls.Add(NewLab3) End Sub Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick Dim NewLab1 As Label NewLab1.Text = Format(ss1, "00:") & Format(tt1, "00:") & Format(vv1, "00.") & Format(ww1, "00.") vv1 = vv1 + 1 If vv1 > 59 Then vv1 = 0 tt1 = tt1 + 1 End If If tt1 = 2 Then vv1 = 0 tt1 = 0 Label1.Text = "00:00:00.00" Timer2.Enabled = False MessageBox.Show("time ended") End If End Sub Private Sub NewBut1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Timer2.enabled = True End Sub Private Sub Button21_Click(sender As Object, e As EventArgs) Handles Button21.Click Timer1.Enabled = True End Sub Sub newlab1() End Sub End Class
问题根源
- 空引用直接访问:
Timer2_Tick事件里声明了Dim NewLab1 As Label但未初始化,直接调用NewLab1.Text触发空引用异常 - 局部变量无法跨方法访问:动态创建的
NewLab1是Button2_Click里的局部变量,Timer2无法直接获取这个控件实例 - 控件重叠:所有动态添加的控件都使用相同的Y坐标,导致后续添加的控件会覆盖之前的,无法正常交互
- 全局计时器冲突:所有参赛项共用一个
Timer2,多个车辆计时会互相干扰
解决方案
通过封装类管理每个参赛项的控件和计时数据,为每个车辆创建独立计时器,同时优化控件布局避免重叠:
Public Class Form1 ' 封装每个参赛车辆的控件和计时数据 Private Class CarTimerItem Public PitInButton As Button Public PitOutButton As Button Public PitStopLabel As Label Public StintLabel As Label Public Timer3Label As Label Public Timer As Timer Public ss1, tt1, vv1 As Integer ' 调整计时变量,用vv1做百分秒 End Class Private carItems As New List(Of CarTimerItem) Private nextControlTop As Integer = 200 ' 下一个控件的起始Y坐标 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Timer3.Enabled = True End Sub Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick Static ss, tt, vv As Integer Label3.Text = Format(ss, "00:") & Format(tt, "00:") & Format(vv, "00") vv += 1 If vv > 59 Then vv = 0 tt += 1 End If If tt = 2 Then vv = 0 tt = 0 Label3.Text = "00:00:00" Timer1.Enabled = False MessageBox.Show("时间结束") End If End Sub Private Sub Timer3_Tick(sender As Object, e As EventArgs) Handles Timer3.Tick Label2.Text = Format(Now, "hh:mm:ss") End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim carNum = InputBox("添加车辆编号", "车辆编号") If String.IsNullOrEmpty(carNum) Then Return Dim newItem As New CarTimerItem ' 创建Pit IN按钮 newItem.PitInButton = New Button With newItem.PitInButton .BackColor = Color.Red .ForeColor = Color.White .Text = "车辆 " & carNum & " 进站" .Location = New Point(12, nextControlTop) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) AddHandler .Click, Sub(s, args) newItem.Timer.Enabled = Not newItem.Timer.Enabled .Text = If(newItem.Timer.Enabled, "暂停计时", "车辆 " & carNum & " 进站") End Sub End With ' 创建Pit OUT按钮 newItem.PitOutButton = New Button With newItem.PitOutButton .BackColor = Color.Lime .ForeColor = Color.Black .Text = "车辆 " & carNum & " 出站" .Location = New Point(225, nextControlTop) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) AddHandler .Click, Sub(s, args) newItem.Timer.Enabled = False newItem.ss1 = 0 newItem.tt1 = 0 newItem.vv1 = 0 newItem.PitStopLabel.Text = "进站计时" End Sub End With ' 创建进站计时标签 newItem.PitStopLabel = New Label With newItem.PitStopLabel .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(537, nextControlTop) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "进站计时" End With ' 创建阶段计时标签 newItem.StintLabel = New Label With newItem.StintLabel .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(748, nextControlTop) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "阶段计时" End With ' 创建第三个计时标签 newItem.Timer3Label = New Label With newItem.Timer3Label .BackColor = Color.Black .ForeColor = Color.Lime .Location = New Point(953, nextControlTop) .Height = 60 .Width = 188 .Font = New Font("Arial Rounded", 16, FontStyle.Bold) .TextAlign = ContentAlignment.MiddleCenter .Text = "计时器3" End With ' 创建独立计时器 newItem.Timer = New Timer newItem.Timer.Interval = 10 ' 10毫秒更新一次,提升计时精度 AddHandler newItem.Timer.Tick, Sub(s, args) newItem.vv1 += 1 If newItem.vv1 > 99 Then ' 百分秒逻辑 newItem.vv1 = 0 newItem.ss1 += 1 End If If newItem.ss1 > 59 Then newItem.ss1 = 0 newItem.tt1 += 1 End If ' 更新对应车辆的进站计时标签 newItem.PitStopLabel.Text = Format(newItem.tt1, "00:") & Format(newItem.ss1, "00:") & Format(newItem.vv1, "00") End Sub ' 添加控件到窗体 Controls.Add(newItem.PitInButton) Controls.Add(newItem.PitOutButton) Controls.Add(newItem.PitStopLabel) Controls.Add(newItem.StintLabel) Controls.Add(newItem.Timer3Label) ' 保存到列表,方便后续管理 carItems.Add(newItem) ' 下一组控件向下偏移,避免重叠 nextControlTop += 70 End Sub Private Sub Button21_Click(sender As Object, e As EventArgs) Handles Button21.Click Timer1.Enabled = True End Sub End Class
关键修改点
- 封装独立数据:用
CarTimerItem类把每个车辆的按钮、标签和计时变量绑定在一起,确保数据不冲突 - 独立计时器:为每个车辆创建专属
Timer,避免全局计时器的干扰 - 控件布局优化:通过
nextControlTop变量动态调整控件Y坐标,添加的控件不会重叠 - 直接关联事件:用Lambda表达式在创建按钮时直接绑定对应车辆的计时器操作,无需额外的全局事件处理
- 精度优化:调整计时逻辑为百分秒级,提升计时准确性
内容的提问来源于stack exchange,提问作者Dazza
相关产品推荐
相关产品推荐

