如何用C#编写在Windows窗体中更新文本框时的“闪光”效果?
题
我拥有的是一个 C# 语言的 Windows 窗体,带有 7 个文本框。当每个文本框的值被更改并被接受时,它会更新另外 2 或 3 个文本框。我想做的是以某种方式获取那些需要更新的文本框,并使它们以浅色背景色或其他颜色“闪烁”。目的是向用户展示正在更新的内容,并添加了一些技巧。
我不确定是否有一种简单的方法可以做到这一点,这就是我在这里问的原因。我想,我可以在文本框控制背景颜色上使用计时器、while 循环和具有递减 alpha 通道的背景颜色,但我想看看是否有更好的方法。
jQuery UI 有一个“突出显示”效果,可以显示我想要完成的任务(尽管我希望我的速度慢一点)。只要去这里 jQuery UI 效果演示页面, ,从窗口的下拉框中选择“突出显示”,然后单击“运行效果”。
编辑
根据我的时间和资源限制,我必须采用自己的解决方案,但文本框不支持 Hans Passant 提到的透明颜色。因此,我使用了一个自停止定时器,增加 R、G 和 B 值,直到控件完全变白(R=255、G=255、B=255);
编辑2
在我们更新到 .NET 4.0 后,最终使用 George Johnston 解决方案的变体将 flash 事件重新编码为扩展方法。我觉得这是一个更干净的解决方案,并且扩展方法使其自动可供任何人使用 using
它。
解决方案
您可以通过闪烁的文本框旋转一个单独的线程,以免在文本框闪烁期间阻止您的表格被使用。确保调用您的表格,因为螺纹的旋转将需要交叉螺纹。下面的完整解决方案。
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);
}
}
这避免了必须将支持计时器控件放在您的表格上。
其他提示
WPF似乎是完美的。您可以在WPF中构建它,并将其用作hostedelement。添加新项目WPF用户控制,并在XAML中添加:
<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将托管在Element -Host元素内。它的优点在于,您可以在WPF中的视觉样式上做更多的事情,但是,它托管了WPF,为您的解决方案增加了一定的重量...
从中得出自己的班级 TextBox
. 。给它一个 Flash()
开始闪烁的方法。只需更改 BackColor
粉彩。不要使用alpha,这对 TextBox
.
您应该让此类的所有实例共享一个共同的计时器,以便它们同时闪烁。使计时器静态并参考您拥有的实例数。在构造函数中添加到 Dispose(bool)
覆盖。
如果您采取了使用Winforms的方式,那么我的知识有限,我可以建议获得第三方控件来提供帮助。命名的一些是Telerik和Componentone。如果您想要一些Winforms,则可以使用WPF,并在XAML中开发自定义动画(我认为在创建UI状态和动画中类似于Silverlight XAML)。除此之外,我没有经验来提供任何帮助。
根据您的应用程序,执行此操作的一种华丽方法是更改文本框图像的伽玛值。这当然取决于您想投入多少时间,但这当然是可行的。我看过一些关于如何调整图像的伽玛值的教程,并且获取控件的图像是微不足道的。
也就是说,我也相信将文本框的背景色设置为透明是很重要的。从你的措辞中,我只能猜测你想要将颜色从底层控件的背景色淡入文本框的背景色,在这种情况下,问题又变得微不足道。但如果你有即背景图像,您也许应该重新考虑。尽管如此,这仍然是可能的,如果您想要实现这一目标,我可以为您找到一个关于如何执行此操作的链接。
快速简单的解决方案是将文本颜色和背景颜色从白色设置为当前的前景色。
如果您对使用线程不感兴趣,请在乔治·约翰斯顿(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;
}
非常古老的问题,但我认为我会以更现代的答案进行更新,因为在2010年回答最后一个答案时,异步/等待
我还将其更新为使用淡淡的褪色的单闪存,而不是癫痫发作的闪烁眨眼,并更改了键入,以便不限于在文本框上使用它。
由于它使用异步/等待,因此在主线程上可以安全地执行,而无需代表或 InvokeRequired
查看。即使将淡出的持续时间设置为long的时间,您仍然可以在淡出循环运行时与应用程序进行交互。
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);
}
我对颜色和时机进行了硬编码,而不是像其他答案器一样将它们视为功能参数,因为如果我重复使用,我通常希望它们在我的应用程序中相同。