8

在搜索淡化 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);
}

这些哪个更有效?

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

谢谢。

4

7 回答 7

23

忘记计时器(双关语)。

使用 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);
}

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

于 2014-11-07T17:09:41.217 回答
14

因此,首先应该避免 application.DoEvents ,除非您真的知道自己在做什么,并且确定这是对它的适当使用,并且您正在正确使用它。我相当肯定,这里的情况都不是。

接下来,你如何控制衰落的速度?您基本上只是让计算机尽可能快地消失,并依靠操作(和后台进程)的固有开销来使其花费更长的时间。这真的不是很好的设计。您最好指定淡入淡出从一开始需要多长时间,以便在机器之间保持一致。您可以使用 aTimer以适当的设置间隔执行代码,并确保 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();
}
于 2012-09-19T16:29:29.087 回答
4

示例表单淡入

我写了一个专门用于淡入淡出表格的类。它甚至支持ShowDialog和DialogResults。

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

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

示例用法

private void Form1_Shown(object sender, EventArgs e)
{
    Fader.FadeIn(this, Fader.FadeSpeed.Slower);
}
于 2017-03-28T10:04:11.057 回答
3
for (double i = 0; i < 1; i+=0.01)
{
    this.Opacity = i;
    Application.DoEvents();
    System.Threading.Thread.Sleep(0);
}

效率更高,因为浮点除法的数量比浮点加法(不影响 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);
}
于 2012-09-19T15:30:06.493 回答
2

我将 Victor Stoddard 的方法应用于启动画面。我在 Form_Load 事件中使用它来淡入淡出,在 FormClosing 事件中使用它来淡出。 注意:在调用 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       
}
于 2016-11-11T18:17:07.457 回答
1

过去,我习惯于AnimateWindow淡入/淡出生成的表单,该表单在SystemColor.WindowColor.

这个巧妙的小技巧提供了在类似向导的界面中隐藏/交换/显示屏幕的效果。我已经有一段时间没有做过这种事情了,但是我在 VB 中使用了 P/Invoke 并在它自己的线程中运行了 API。

我知道您的问题在 C# 中,但大致相同。这是我挖出来的一些可爱的 VB,自 2006 年以来就没有看过!显然,很容易调整它来淡入淡出你自己的表格。

<DllImport("user32.dll")> _
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
于 2012-09-19T15:52:04.000 回答
1

Victor Stoddard很接近,但我发现如果它开始快速增加不透明度并在接近完全不透明度 1 时减慢渐变会更令人愉悦。以下是对他的代码的轻微修改:

    using System.Threading.Tasks;
    using System.Windows.Forms;

    public partial class EaseInForm : Form
    {
        public EaseInForm()
        {
            InitializeComponent();
            this.Opacity = 0;
        }

        private async void Form_Load(object sender, EventArgs e)
        {
            while (this.Opacity < 1.0)
            {
                var percent = (int)(this.Opacity * 100);
                await Task.Delay(percent);
                this.Opacity += 0.04;
            }
        }
    }
于 2020-06-30T16:53:12.947 回答