【问题标题】:Button on the form doesn't get new color表单上的按钮没有获得新颜色
【发布时间】:2016-06-25 20:30:36
【问题描述】:

这是我目前所拥有的

Private Sub BtnAnswerA_Clicked(sender As Object, e As EventArgs) Handles btnAnswerA.Click
    Me.btnAnswerA.BackColor = Color.Green
    System.Threading.Thread.Sleep(10000)
    Me.Hide()
    Q2.Show()
End Sub

我想,当按钮被点击时,它会改变颜色。然后,10 秒后,它将打开另一个表单。但它会等待 10 秒,然后再打开下一个表单而不更改颜色。

【问题讨论】:

  • 使用计时器。 Sleep 锁定了 UI 线程,所以什么也没有发生
  • @T.S.使用Application.DoEvents 几乎总是一种隐藏您在程序中做错了什么的方式。
  • @T.S.那么请不要以糟糕的技术开始 OP ;)
  • @AndrewMorton 让我和你分享一些东西。汉斯在这里享有盛誉stackoverflow.com/a/5183623/1704458
  • @T.S.是的,他解释了为什么使用Application.DoEvents() 是个坏主意除非你也做其他事情。

标签: vb.net button background-color


【解决方案1】:

猜测一下,您可能希望显示其他形式,并且可能具有不同的延迟。您可以使用以表单和延迟作为参数的 Sub 来做到这一点。

假设您使用的是 VS2010 或更高版本,您的代码可能如下所示:

Private Sub ShowNextForm(formToShow As Form, secondsDelay As Double)
    Dim tim As New System.Windows.Forms.Timer
    tim.Interval = CInt(secondsDelay * 1000)
    tim.Start()
    AddHandler tim.Tick, Sub(sender As Object, e As EventArgs)
                             tim.Stop()
                             tim.Dispose()
                             Me.Hide()
                             formToShow.Show()
                         End Sub
End Sub

Private Sub btnAnswerA_Click(sender As Object, e As EventArgs) Handles btnAnswerA.Click
    Dim bn = DirectCast(sender, Button)
    bn.Enabled = False
    bn.BackColor = Color.Green
    Dim nextForm As New Q2
    ShowNextForm(nextForm, 10)

End Sub

然后,如果你有另一个按钮,你想做同样的事情,说“btnAnswer99”表格z99和延迟2.5秒,你只需要编写代码

Private Sub btnAnswer99_Click(sender As Object, e As EventArgs) Handles btnAnswer99.Click
    Dim bn = DirectCast(sender, Button)
    bn.Enabled = False
    bn.BackColor = Color.Blue
    Dim nextForm As New z99
    ShowNextForm(nextForm, 2.5)

End Sub

变得更高级...也许稍后再看...

您可能会注意到您为每个按钮重复了很多代码。现在是时候考虑重构你的代码了,这样你只需要编写一次基本的代码,并且有参数来决定它的作用。

因此,您可以查看所有按钮单击处理程序之间的共同点,例如它们都有一个它们所在的表单、一个要显示的表单、一些要更改为的 BackColor,以及显示下一个表单之前的延迟,以及当然,他们指的是 a 按钮。

这是创建一个来封装所有部分的理想机会,可能有点像这样:

Friend Class SetButtonToShowForm

    Property thisForm As Form
    Property nextForm As Form
    Property buttonRef As Button
    Property buttonBackColor As Color
    Property secondsDelay As Double

    Friend Sub ShowNextForm(currentForm As Form, formToShow As Form, secondsDelay As Double)
        Dim tim As New System.Windows.Forms.Timer
        tim.Interval = CInt(secondsDelay * 1000)
        tim.Start()
        AddHandler tim.Tick, Sub(sender As Object, e As EventArgs)
                                 tim.Stop()
                                 tim.Dispose()
                                 currentForm.Hide()
                                 formToShow.Show()
                             End Sub

    End Sub

    Friend Sub bnClick(sender As Object, e As EventArgs)
        Dim bn = DirectCast(sender, Button)
        bn.Enabled = False
        bn.BackColor = Me.buttonBackColor

        ShowNextForm(thisForm, nextForm, secondsDelay)

    End Sub

    Public Sub New()
        ' empty constructor
    End Sub

    Public Sub New(sourceForm As Form, targetForm As Form, buttonRef As Button, backColor As Color, secondsDelay As Double)
        Me.thisForm = sourceForm
        Me.nextForm = targetForm
        Me.buttonRef = buttonRef
        Me.buttonBackColor = backColor
        Me.secondsDelay = secondsDelay
        AddHandler Me.buttonRef.Click, AddressOf bnClick

    End Sub

End Class

然后您可以按照以下步骤在一个过程中设置所有按钮

Private Sub SetButtonHandlers()
    Dim b1 As New SetButtonToShowForm(Me, Q2, btnAnswerA, Color.Green, 5)
    Dim b2 As New SetButtonToShowForm(Me, z99, btnAnswer99, Color.Blue, 2.3)
End Sub

因此您可以看到,只需一点 多一点努力,就可以更加轻松地设置更多按钮。

【讨论】:

  • 有趣的是,当可怜的家伙与DoEvents一起工作时,你花了这么多时间在这上面。
【解决方案2】:

见代码

Private Sub BtnAnswerA_Clicked(sender As Object, e As EventArgs) Handles btnAnswerA.Click
    Me.btnAnswerA.BackColor = Color.Green
    Application.DoEvents()   ' <--- THERE
    System.Threading.Thread.Sleep(10000)
    Me.Hide()
    Q2.Show()
End Sub

发生什么,无论发生什么,都发生得如此之快,您的表单/按钮没有时间重新绘制。在这些情况下,您使用DoEvents 告诉应用程序在处理下一条消息之前完成队列中的所有消息。它完成绘画,然后开始休眠,因此显示一个绿色按钮。

DoEvents 带来意见。我喜欢这个https://stackoverflow.com/a/5183623/1704458

人们被DoEvents 冒犯了,但它从未让我失望。好的。这是我为@Plutonix 写的内容

private _timer As new System.Timers.Timer(10000)
Private Sub Form_Load(sender As Object, e As EventArgs)
    AddHandler _timer.Elapsed, AddressOf OnElapsed
End Sub

Private Sub BtnAnswerA_Clicked(sender As Object, e As EventArgs) Handles btnAnswerA.Click
    Me.btnAnswerA.BackColor = Color.Green
    Me.btnAnswerA.Enabled = False
    _timer.Enabled = True 
End Sub

Private Sub OnElapsed (sender As Object, e As ElapsedEventArgs)
    _timer.Enabled = False 
    Me.btnAnswerA.Enabled = True
    Me.Hide()
    Q2.Show()
End Sub

Timer Elapsed 在不同的线程上运行,因此您的表单将响应而不是冻结

【讨论】:

  • @T.S.我找不到任何文档表明 Windows.Forms.Timer 使用单独的线程。 Windows.Forms.Timer Class 的文档特别指出“此 Windows 计时器是为单线程环境设计的,其中 UI 线程用于执行处理。” (对不起,我不是有意对你不友善,但你写的东西错误。)
  • @AndrewMorton 你很困惑。我的例子是使用System.Timers.Timer。这里是 MSDN:事件处理方法可能在一个线程上运行,同时另一个线程调用 Stop 方法...这意味着命令 Stop 可以来自不同的线程Elapsed 运行的线程。此处:albahari.com/threading/part3.aspx - 搜索 多线程计时器
猜你喜欢
  • 1970-01-01
  • 2021-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 2018-07-27
  • 1970-01-01
  • 2014-08-05
相关资源
最近更新 更多