【问题标题】:How do I program a "flash" effect when updating text boxes in a windows form with C#?使用 C# 更新 windows 窗体中的文本框时,如何编写“flash”效果?
【发布时间】:2011-05-08 00:36:10
【问题描述】:

我有一个 Windows 窗体,用 C# 编写,有 7 个文本框。当其值被更改并被接受时,每个文本框都会更新 2 或 3 个其他文本框。我想做的是以某种方式获取那些需要更新的文本框,并用浅色背景或其他东西使它们“闪烁”。目的是向用户展示正在更新的内容,并增加一点天赋。

我不确定是否有一种简单的方法可以做到这一点,这就是我在这里问的原因。我认为,我可以在文本框控件背景色上使用计时器、while 循环和带有递减 alpha 通道的背景色,但我想看看是否有更好的方法。

jQuery UI 有一个“突出显示”效果,它显示了我想要完成的事情(虽然我希望我的要慢一点)。直接到jQuery UI Effects Demo page这里,在窗口的下拉框中选择“高亮”,然后点击“运行效果”。

编辑
根据我的时间和资源限制,我不得不采用自己的解决方案,但文本框不支持 Hans Passant 提到的透明颜色。所以,我使用了一个自停计时器,它增加了 R、G 和 B 的值,直到控件完全变白(R=255,G=255,B=255);

编辑 2
在我们更新到 .NET 4.0 之后,使用 George Johnston 解决方案的变体将 flash 事件重新编码为一种扩展方法。我觉得这是一个更清洁的解决方案,并且扩展方法可以自动提供给任何人using 它。

【问题讨论】:

  • 我认为您的方法是直接的解决方案。 JQuery 的简单之处在于网页...
  • 是的。 jQuery 链接的目的是给出一个我想要完成的可视化示例。
  • 基于时间限制和其他限制,我想如果我的想法可以的话,我必须接受那个。根据我的经验和可用资源,这是迄今为止最简单、最容易/最快的编码。所有这些都是很好的答案,我很感激你的意见。我用我正在使用的新方法更新了我的问题。

标签: c# winforms animation textbox backcolor


【解决方案1】:

相当老的问题,但我想我会更新一个更现代的答案,因为在 2010 年最后一个答案得到回答时,async/await 并不存在

我还对其进行了更新,以使用一个很好的渐变单闪而不是引起癫痫发作的开关闪烁,并更改了打字方式,使其不限于在文本框上使用。

由于它使用 async/await,因此在主线程上执行操作是安全的,无需委托或 InvokeRequired 检查。即使您将淡入淡出的持续时间设置为较长,您仍然可以在淡入淡出循环运行时与应用程序进行交互。

    private bool CurrentlyFlashing = false;
    private async void FlashControl(Control control)
    {
        Color flashColor = Color.Yellow;

        float duration = 500; // milliseconds
        int steps = 10;
        float interval = duration / steps;

        if (CurrentlyFlashing) return;
        CurrentlyFlashing = true;
        Color original = control.BackColor;

        float interpolant = 0.0f;
        while (interpolant < 1.0f)
        {
            Color c = InterpolateColour(flashColor, original, interpolant);
            control.BackColor = c;
            await Task.Delay((int) interval);
            interpolant += (1.0f / steps);
        }

        control.BackColor = original;

        CurrentlyFlashing = false;
    }

    public static Color InterpolateColour(Color c1, Color c2, float alpha)
    {
        float oneMinusAlpha = 1.0f - alpha;
        float a = oneMinusAlpha * (float)c1.A + alpha * (float)c2.A;
        float r = oneMinusAlpha * (float)c1.R + alpha * (float)c2.R;
        float g = oneMinusAlpha * (float)c1.G + alpha * (float)c2.G;
        float b = oneMinusAlpha * (float)c1.B + alpha * (float)c2.B;
        return Color.FromArgb((int)a, (int)r, (int)g, (int)b);
    }

我对颜色和时间进行了硬编码,而不是像其他回答者那样将它们作为函数参数公开,因为如果我重用它,我通常希望它们在我的应用程序中保持相同。

【讨论】:

    【解决方案2】:

    TextBox 派生您自己的类。给它一个启动闪烁的Flash() 方法。只需将BackColor 更改为柔和的颜色即可。不要使用 alpha,它不适用于 TextBox

    您应该让该类的所有实例共享一个公共 Timer,以便它们同时闪烁。使计时器静态并引用计数您拥有的实例数。在构造函数中添加,在 Dispose(bool) 覆盖中添加。

    【讨论】:

    • 这是个好主意,我可能会在以后实现。我一直在考虑为特殊格式和验证制作自己的派生文本框,因此这可能在该项目的范围内。
    【解决方案3】:

    如果您对使用线程不感兴趣,那么基于 George Johnston 的回答,我的实现如下:

    private bool CurrentlyFlashing = false;
    private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
    {
        if (CurrentlyFlashing) return;
    
        CurrentlyFlashing = true;
        Color original = textBox.BackColor;
        for (int i = 0; i < flashes; i++)
        {
            UpdateTextbox(textBox, flashColor);
            Application.DoEvents();
            Thread.Sleep(interval / 2);
            UpdateTextbox(textBox, original);
            Application.DoEvents();
            Thread.Sleep(interval / 2);
        }
        CurrentlyFlashing = false;
    }
    private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
    public void UpdateTextbox(TextBox textBox, Color color)
    {
        if (textBox.InvokeRequired)
        {
            this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
        }
        textBox.BackColor = color;
    }
    

    【讨论】:

      【解决方案4】:

      您可以为每个闪烁的文本框分离一个单独的线程,以免在您的文本框闪烁期间阻止您的表单被使用。请务必调用您的表单,因为线程的旋转将需要交叉线程。完整解决方案如下。

      private void Form1_Load(object sender, EventArgs e)
      {
          // textBox1 is the control on your form.
          // 1000 is the total interval between flashes
          // Color.LightBlue is the flash color
          // 10 is the number of flashes before the thread quits.
          Flash(textBox1, 1000,Color.LightBlue,10);
          Flash(textBox2, 1500,Color.Green,10);
          Flash(textBox3, 100,Color.Red,10);
          Flash(textBox4, 500,Color.Brown,10);
          Flash(textBox5, 200,Color.Pink,10);
      }
      
      public void Flash(TextBox textBox, int interval, Color color, int flashes)
      {
          new Thread(() => FlashInternal(textBox, interval, color, flashes)).Start();
      }
      
      private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
      public void UpdateTextbox(TextBox textBox, Color color)
      {
          if (textBox.InvokeRequired)
          {
              this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
          }
          textBox.BackColor = color;
      }
      
      private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
      {
          Color original = textBox.BackColor;
          for (int i = 0; i < flashes; i++)
          {
      
              UpdateTextbox(textBox, flashColor);
              Thread.Sleep(interval/2);
              UpdateTextbox(textBox, original);
              Thread.Sleep(interval/2);
          }
      }
      

      这避免了必须在表单上放置支持的计时器控件。

      【讨论】:

      • 哇。这是一个好主意,虽然我需要老板继续从 .NET 2.0 迁移。截至目前,这是我们的目标框架,不支持 Lambda 表达式。我也不认为我可以及时获取此代码并使用该项目。不过,我们非常感谢您的帮助。
      • 我们不久前更新到 .NET 4,所以我最终重新编写了 flash 事件并使用了您的解决方案的变体。使用了扩展方法,因此您只需调用myTextBox.Flash(...)。 :) 感谢您的建议。
      【解决方案5】:

      WPF 似乎很适合这个。您可以在 WPF 中构建它并在 WinForms 中将其用作 HostedElement。 在 xaml 中添加新项目 WPF 用户控件:

      <UserControl x:Class="WpfControlLibrary1.UserControl1"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
               xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
               mc:Ignorable="d" 
               d:DesignHeight="20" d:DesignWidth="300">
      <TextBox>
          <TextBox.Triggers>
              <EventTrigger RoutedEvent="TextBox.TextChanged">
                  <BeginStoryboard>
                      <Storyboard AutoReverse="False" BeginTime="0" >
                          <DoubleAnimation Storyboard.TargetName="Foo"
                                       Storyboard.TargetProperty="Opacity"
                                       From="0" To="1" Duration="0:0:1"/>
                      </Storyboard>
                  </BeginStoryboard>
              </EventTrigger>
          </TextBox.Triggers>
          <TextBox.Background>
              <SolidColorBrush Opacity="1" x:Name="Foo" Color="LightGray" />
          </TextBox.Background>
      </TextBox>
      </UserControl>
      

      (它可以做一些工作,但这是一个开始)。你有它 - 一个花哨的文本框:)

      构建解决方案,工具箱中将出现一个新项目 - 只需拖放到您的表单,WPF 将托管在 ElementHost 元素内。它的美妙之处在于您可以在 WPF 中对视觉样式做更多的事情,但是,它是托管的 WPF,这为您的解决方案增加了一定的权重......

      【讨论】:

      • 我以前从未使用过 WPF。这真的很酷。但是,由于目前没有时间学习,并且项目没有转换为 .NET 4.0(我们必须等待老板批准才能转换),我不得不采用不同的答案。不过,我会检查 WPF。
      【解决方案6】:

      根据您的应用,一种华丽的方法是更改​​文本框图像的伽玛。这当然取决于你想投入多少时间,但这当然是可行的。我已经看过几个关于如何调整图像的 gamma 和获取控件图像的教程。

      也就是说,我也相信将文本框的背景色设置为透明是不平凡的。从您的措辞中,我只能猜测您想将颜色从底层控件的背景色淡化为文本框的背景色,在这种情况下,问题又是微不足道的。但是如果你有背景图片,你也许应该重新考虑。尽管如此,它仍然是可能的,如果这是你想要完成的,我可以为你挖掘一个链接,告诉你如何做到这一点。

      快速简单的解决方案是将文本颜色和背景颜色从白色变为当前前景颜色。

      【讨论】:

        【解决方案7】:

        如果您已准备好使用 WinForms,那么以我有限的知识,我可以建议您使用第三方控件来提供帮助。 Telerik 和 ComponentOne 就是其中的几个例子。如果您想要类似 WinForms 的东西,您可能可以使用 WPF,并在 XAML 中开发自定义动画(我认为在创建 UI 状态和动画方面类似于 Silverlight XAML)。除了这些,我没有经验提供任何帮助。

        【讨论】:

        • 当您可以在派生控件中非常简单地实现此处所寻求的效果时,我似乎没有什么令人信服的理由来假设第三方控件库的潜在困难。想知道是否有任何第三方控件以不同于问题建议的方式实现此功能。
        猜你喜欢
        • 1970-01-01
        • 2022-08-23
        • 2011-01-29
        • 1970-01-01
        • 2012-01-23
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多