更好的算法来淡化winform

afa*_*lek 8 c# winforms fading

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

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

for环具有非整数递增,并从以前的问题,我问,这不是一个很好的编程技术(由于大多数小数的不精确表示).

我提出了这个替代方案.

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

哪个更有效?

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

谢谢.

Vic*_*ard 20

忘记计时器(双关语).

使用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       
}
Run Code Online (Sandbox Code Playgroud)

用法:

private void button1_Click(object sender, EventArgs e)
{
    FadeOut(this, 100);
}
Run Code Online (Sandbox Code Playgroud)

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


Ser*_*rvy 13

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

接下来,你如何控制褪色的速度?你基本上只是让计算机尽可能快地消失,并依赖于操作(和后台进程)的固有开销来使它花费更长的时间.这真的不是很好的设计.你最好指定淡入淡出应该从一开始就需要多长时间才能在机器之间保持一致.您可以使用a 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();
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个精明的评论,我特别喜欢您坚持“应该避免DoEvent”的事实,这确实应该。我也做类似的事情,但是您缺少重要的事情:您应该在某个时间停止计时器!!!在Tick处理程序中,加入`if(Opacity&gt; = 1.0){timer.Stop(); timer.Dispose(); }` (2认同)

Nat*_* F. 5

示例表单淡入

我写了一个专门用于淡入淡出表单的类。它甚至支持ShowDialogDialogResults。

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

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

示例用法

private void Form1_Shown(object sender, EventArgs e)
{
    Fader.FadeIn(this, Fader.FadeSpeed.Slower);
}
Run Code Online (Sandbox Code Playgroud)


Ani*_*nge 3

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

效率更高,因为浮点除法的数量比浮点加法(不影响 vm-flags)更昂贵。也就是说,您可以将迭代次数减少 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);
}
Run Code Online (Sandbox Code Playgroud)