【问题标题】:Timer in C# is acting very strangelyC# 中的计时器表现得很奇怪
【发布时间】:2019-01-26 05:06:20
【问题描述】:

我不确定这段代码有什么问题。 timer1 间隔设置为 1000。

namespace timerbug
{
    public partial class Form1 : Form
    {
        int value;

        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            do
            {
                value++;
                label1.Text = value.ToString();
            }
            while (value <= 5);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            value = 0;
            timer1.Start();
        }
    }
}

我以为标签会显示 1 到 5,然后停止。计数直到 6 点才出现,并继续上升,直到我停止程序。有人可以解释为什么数字 1 到 5 没有出现,然后为什么它没有停在 5 上?谢谢。

【问题讨论】:

  • 因为 UI 在消息泵运行之前不会更新。您可以通过将Application.DoEvents() 添加到循环主体来强制执行此操作,但强烈建议不要这样做。请查看this quesiton 了解更多信息。
  • 它不会在 5 处停止,因为您有一个 do..while 循环,而不是 while 循环
  • 如果我是你,我会使用调试器并逐行执行代码。在timer1_Tick 中,在while 语句之后放置一个断点。观察 value(它是 6,因为这是第一个 not timer1_Tick 的顶部放置一个断点。继续运行。一秒钟后它将在顶部。观察value(仍然是6)。单步执行代码。注意do..while 循环的主体已运行(因为它还没有达到while 条件)......
  • 我认为,与其在Tick 事件中循环更新值,不如只更新一次。但首先检查它是否已经是5,如果是,则停止计时器。比如:if (value &lt; 5) label1.Text = ++value.ToString(); else timer1.Stop();

标签: c# loops timer


【解决方案1】:

正如其他人在 cmets 中正确指出的那样,它停在6 而不是5 因为6value &lt;= 5 评估为假的第一个值(您正在使用do-while 循环,这意味着在执行主体后评估条件。)。为了在5 停止,您可以使用常规的while 循环或将条件更改为value &lt; 5value &lt;= 4

此外,C# 中循环的 6 次迭代发生在几微秒内。即使其他一切都正确完成,您也无法真正看到标签中显示的数字,仅仅是因为它发生得太快了。为了看到任何事情发生,您需要引入某种延迟 (Thread.Sleep()),并且在每次迭代结束时,您必须调用 Application.DoEvents() 让表单重新绘制。

或者,您可以使用Timer 的刻度,这在大多数情况下会更可取。例如,您可以这样做。

namespace timerbug
{
    public partial class Form1 : Form
    {
        int value;

        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (value < 5)
            {
                value++;
                label1.Text = value.ToString();
            }
            else
            {
                timer1.Stop();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            value = 0;
            timer1.Start();
        }
    }
}

【讨论】:

  • 谢谢。我下面的解决方案利用了这一点,并且还使用 Invalidate 和 Update 语句进行了更新。
【解决方案2】:

将 timer1_tick 代码更改为此工作正常,感谢您的帮助。我有很多东西要学。

        value++;

        if (value >= 5)
        {
            timer1.Stop();
        }

            label1.Text = value.ToString();
            label1.Invalidate();
            label1.Update();

        }

【讨论】:

  • 没有理由使标签无效或更新。您只需更改它,它就会自行更新。
  • 是的,我明白了,你是对的。但是,当绘制/绘画(而不仅仅是标签)时,我需要语句来更新屏幕,因为滴答声发生而不是在全部完成之后。这部分是我的小测试。谢谢。
猜你喜欢
  • 2020-05-03
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-23
  • 2014-12-12
  • 2012-11-11
  • 1970-01-01
相关资源
最近更新 更多