更好的算法来淡化winform

在搜索代码以淡化winform时,我在MSDN论坛上看到了这个页面 。

for (double i = 0; i < 1; i+=0.01) { this.Opacity = i; Application.DoEvents(); System.Threading.Thread.Sleep(0); } 

for循环有一个非整数增量,从我之前提出的问题来看,这不是一个好的编程技术(由于大多数小数的不精确表示)。

我提出了这个替代方案。

 for (double i = 0; i < 100; ++i) { this.Opacity = i/100; Application.DoEvents(); System.Threading.Thread.Sleep(0); } 

哪个更有效?

如果有一个更好的淡化表格的算法,如果包含它,我会很高兴。

谢谢。

忘记计时器(双关语)。

使用Visual Studio 4.5或更高版本,您可以await延迟的任务。 这种方法的一个优点是它是异步的,不像线程SleepDoEvents循环,它在淡入淡出期间阻塞应用程序(以及其他上述的DoEvents问题)。

 private async void FadeIn(Form o, int interval = 80) { //Object is not fully invisible. Fade it in while (o.Opacity < 1.0) { await Task.Delay(interval); o.Opacity += 0.05; } o.Opacity = 1; //make fully visible } private async void FadeOut(Form o, int interval = 80) { //Object is fully visible. Fade it out while (o.Opacity > 0.0) { await Task.Delay(interval); o.Opacity -= 0.05; } o.Opacity = 0; //make fully invisible } 

用法:

 private void button1_Click(object sender, EventArgs e) { FadeOut(this, 100); } 

在对对象应用任何透明度之前,应检查对象是否已被处置。 我使用表单作为对象,但只要正确转换,您就可以传递任何支持透明度的对象。

所以,首先, 应该避免使用application.DoEvents,除非你真的知道自己在做什么,并确保这是对它的适当使用,并且你正确使用它。 我很确定这里的情况都不是这样。

接下来,你如何控制褪色的速度? 你基本上只是让计算机尽可能快地消失,并依赖于操作(和后台进程)的固有开销来使它花费更长的时间。 这真的不是很好的设计。 你最好指定淡入淡出应该从一开始就需要多长时间才能在机器之间保持一致。 您可以使用Timer以适当的设置间隔执行代码,并确保在淡入淡出期间不阻止UI线程(不使用DoEvents )。

只需修改下面的duration即可更改淡入淡出所需的时间,并修改steps以确定它是如何“波动”的。 我把它设置为100,因为这实际上是你的代码以前做的。 实际上,你可能不需要那么多,你可以降低到它开始变得不稳定之前。 (步骤越低,表现越好。)

另外,你不应该担心这样的表现。 褪色是需要以大约一秒或不太小的程度(对于能够感知它的人)来衡量的东西,并且对于任何计算机这些天它都可以这样做,远远超过这个在一秒钟内,它甚至都不好笑。 在一秒钟内计算方面几乎不会消耗CPU,因此尝试优化它绝对是微优化。

 private void button1_Click(object sender, EventArgs e) { int duration = 1000;//in milliseconds int steps = 100; Timer timer = new Timer(); timer.Interval = duration / steps; int currentStep = 0; timer.Tick += (arg1, arg2) => { Opacity = ((double)currentStep) / steps; currentStep++; if (currentStep >= steps) { timer.Stop(); timer.Dispose(); } }; timer.Start(); } 
 for (double i = 0; i < 1; i+=0.01) { this.Opacity = i; Application.DoEvents(); System.Threading.Thread.Sleep(0); } 

因为与浮点加法(不影响vm标志)相比,浮点除法的数量更加昂贵,所以效率更高。 也就是说,您可以将迭代次数减少1/2(即将步骤改为i + = 0.02)。 1%的不透明度降低不会被人脑明显降低,并且也会降低成本,加快几乎100%。

编辑:

 for(int i = 0; i < 50; i++){ this.Opacity = i * 0.02; Application.DoEvents(); System.Threading.Thread.Sleep(0); } 

示例表格淡入

我写了一个专门针对淡入淡出forms的课程。 它甚至支持ShowDialog和DialogResults。

我已经扩展了它,因为我需要新的function,并且愿意接受建议。 你可以看看这里:

https://gist.github.com/nathan-fiscaletti/3c0514862fe88b5664b10444e1098778

示例用法

 private void Form1_Shown(object sender, EventArgs e) { Fader.FadeIn(this, Fader.FadeSpeed.Slower); } 

我将Victor Stoddard的方法应用于splashScreen。 我在Form_Load事件中使用它将fadeIn和FormClosing事件用于fadeOut。 注意:在调用fadeIn方法之前,我必须将窗体的不透明度设置为0。

在这里,您可以看到winform(生命周期)所引发的事件顺序: https ://msdn.microsoft.com/en-us/library/86faxx0d( v = vs.110).aspx

 private void Splash_Load(object sender, EventArgs e) { this.Opacity = 0.0; FadeIn(this, 70); } private void Splash_FormClosing(object sender, FormClosingEventArgs e) { FadeOut(this, 30); } private async void FadeIn(Form o, int interval = 80) { //Object is not fully invisible. Fade it in while (o.Opacity < 1.0) { await Task.Delay(interval); o.Opacity += 0.05; } o.Opacity = 1; //make fully visible } private async void FadeOut(Form o, int interval = 80) { //Object is fully visible. Fade it out while (o.Opacity > 0.0) { await Task.Delay(interval); o.Opacity -= 0.05; } o.Opacity = 0; //make fully invisible } 

在过去,我使用AnimateWindow淡入/淡出生成的表单,该表单在SystemColor.WindowColor覆盖整个应用程序。

这个巧妙的小技巧可以在类似界面的向导中隐藏/交换/显示屏幕。 我暂时没有做过这种事情,但我在VB中使用了P / Invoke并在自己的线程中运行了API。

我知道你的问题是在C#中,但它大致相同。 这是一些可爱的VB我已经挖出来,自2006年以来没有看过! 显然,很容易适应这种方式来淡化你自己的forms。

  _ Public Shared Function AnimateWindow(ByVal hwnd As IntPtr, ByVal dwTime As Integer, ByVal dwFlags As AnimateStyles) As Boolean End Function Public Enum AnimateStyles As Integer Slide = 262144 Activate = 131072 Blend = 524288 Hide = 65536 Center = 16 HOR_Positive = 1 HOR_Negative = 2 VER_Positive = 4 VER_Negative = 8 End Enum Private m_CoverUp As Form Private Sub StartFade() m_CoverUp = New Form() With m_CoverUp .Location = Me.PointToScreen(Me.pnlMain.Location) .Size = Me.pnlMain.Size .FormBorderStyle = System.Windows.Forms.FormBorderStyle.None .BackColor = Drawing.SystemColors.Control .Visible = False .ShowInTaskbar = False .StartPosition = System.Windows.Forms.FormStartPosition.Manual End With AnimateWindow(m_CoverUp.Handle, 100, AnimateStyles.Blend) 'Blocks Invoke(New MethodInvoker(AddressOf ShowPage)) End Sub Private Sub EndFade() AnimateWindow(m_CoverUp.Handle, 100, AnimateStyles.Blend Or AnimateStyles.Hide) m_CoverUp.Close() m_CoverUp = Nothing End Sub