【问题标题】:Button-Color only gets updated AFTER completing the Paint-MethodButton-Color 仅在完成 ​​Paint-Method 后更新
【发布时间】:2019-03-17 13:40:55
【问题描述】:

使用 Button-Paint-Event 按钮不会在 for 循环的每次迭代中更新。但是每次迭代都会平滑地更新表单或面板。

因此,在执行此代码时,Button 以默认颜色开始,然后在 for 循环完成后,显示颜色数组中的最后一种颜色。 它不会随着每次迭代而更新。

我的问题:有人知道,为什么每次迭代都没有更新 Button,但其他控件使用相同的代码?

void Main()
{
    Color[] colors = new Color[10]
    {
        Color.White, Color.Red, Color.Blue, Color.Green, Color.Black,
        Color.Purple, Color.Brown, Color.Yellow, Color.Gray, Color.Lime
    };

    Button button = new Button();
    button.FlatStyle = FlatStyle.Flat;
    button.Paint += (sender, e) =>
    {
        for (int i = 0; i < 10; i++)
        {
            e.Graphics.FillRectangle(
                new SolidBrush(colors[i]),
                new RectangleF(0, 0, button.Width, button.Height));

            Thread.Sleep(100);
            Application.DoEvents();
        }
    };

    Form form = new Form();
    form.Controls.Add(button);
    form.Show();
}

【问题讨论】:

  • Paint 事件很特别。 - 不要尝试在 Paint 事件中制作动画。您无法控制它,应该让系统使用它,包括任何优化。您可以将该循环移到外面并在每次睡眠后调用 Invalidate 或按照建议使用计时器,这是动画的正常方式..
  • 为什么我无法控制它?我可以实现不同的方法来应对不同的不同情况。除了按钮问题之外,我还没有遇到任何问题。
  • 因为系统也需要调用它;并且在优化它时会很随意。顺便说一句:10 * 100 ms = 1second
  • "10 * 100ms = 1 秒。"...所以?这个例子是为了解决问题和问题。这不是最终的实现,只是一个简化版本。基础的 Paint 事件仍然会被调用,这只是“额外的”。

标签: c# forms button paint doevents


【解决方案1】:

我的问题:有人知道,为什么 Button 没有更新 每次迭代,但其他控件都使用相同的代码?

不知道。

不过,您的方法一开始就有缺陷。您永远不应该在主 UI 线程中使用 Sleep(),因为它可能导致 UI 无响应。此外,对 DoEvents() 的调用可能会导致更多 Paint() 事件发生(可重入代码)。

使用 Timer 控件并从那里更改 Button 的 BackColor

下面是一个简单的例子,它使用 Enumerator 反复循环颜色:

static void Main()
{
    Color[] colors = new Color[10]
    {
        Color.White, Color.Red, Color.Blue, Color.Green, Color.Black,
        Color.Purple, Color.Brown, Color.Yellow, Color.Gray, Color.Lime
    };
    IEnumerator colorEnum = colors.GetEnumerator();

    Button button = new Button();
    button.FlatStyle = FlatStyle.Flat;

    System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
    tmr.Interval = 250;
    tmr.Tick += (s, e) =>
    {
        if (!colorEnum.MoveNext())
        {
            colorEnum.Reset();
            colorEnum.MoveNext();
        }
        button.BackColor = (Color)colorEnum.Current;
    };

    Form form = new Form();
    form.Shown += (s, e) =>
    {
        tmr.Start();
    };
    form.Controls.Add(button);

    Application.Run(form);
}

【讨论】:

  • 好吧,正如我所说,我将其压缩到最低限度。我的真实代码会有一个布尔值来检查绘制事件是否已经在执行。睡眠时间为 1 毫秒,这应该会导致完美响应的 UI。我会记住你的方法,也许这只是一种更可靠的方法。
  • 小睡眠只会导致按钮超快闪烁;没有足够的时间看到当前的颜色。显然,您可以编写一个循环来延迟指定的时间以“修复”这个问题,但它会“响应”的唯一原因是由于 DoEvents() 调用,这是一个直接的危险信号,表明这是错误的做法。 =)
  • ...你从来没有提到这是精简/裸露的最低代码。
  • 没错。我剪掉了我的原文,以免过分夸大帖子。对此感到抱歉。我认为不会发生闪烁。例如,它将从深灰色混合到浅灰色。或从钢蓝色到青色。那样的颜色。为什么调用 DoEvents 是错误的?
  • DoEvents() 是让 StackOverflow 陷入两极狂热的 cmets 的最快方法之一。请参阅Is DoEvents Evil? 进行一次讨论。总是错的吗?...不。但总的来说,通常有更好的方法来完成任务。
猜你喜欢
  • 2011-12-14
  • 2021-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
相关资源
最近更新 更多