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は、自分が何をしているのかを本当に理解していて、これが適切な使用法であり、正しく使用していることを確認しない限り、避ける必要があります。ここではどちらも当てはまらないと確信しています。

次に、フェードの速度をどのように制御していますか?基本的には、コンピューターをできるだけ早くフェードさせ、操作(およびバックグラウンドプロセス)に固有のオーバーヘッドに依存して、コンピューターの処理時間を長くします。それは本当に良いデザインではありません。フェードがマシン間で一貫するように、最初からフェードにかかる時間を指定することをお勧めします。を使用しTimerて、適切な設定間隔でコードを実行し、フェードの期間中(を使用せずにDoEvents)UIスレッドがブロックされないようにすることができます。

以下を変更durationしてフェードにかかる時間を変更し、を変更しstepsて「途切れ途切れ」を判断します。100に設定したのは、それが事実上、以前のコードで行われていたことだからです。実際には、おそらくそれほど多くは必要なく、途切れ始める直前まで下げることができます。(ステップが低いほど、パフォーマンスが向上します。)

さらに、このようなパフォーマンスについてはそれほど心配する必要はありません。フェードは、約1秒またはそれ以下のスケールで測定する必要があるものであり(人間がそれを認識できるようにするため)、最近のどのコンピューターでも、これよりはるかに多くのことができます。一瞬でそれも面白くありません。これは、1秒間の計算に関して、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

フォームのフェードインの例

フォームのフェードインとフェードアウト専用のクラスを作成しました。ShowDialogDialogResultsもサポートしています。

私は新しい機能が必要だったのでそれを拡張し、提案を受け付けています。ここで見ることができます:

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

ビクター・ストッダードのアプローチをスプラッシュスクリーンに適用しました。Form_LoadイベントでfadeInに、FormClosingイベントでfadeOutに使用しました。 注: フォームの不透明度を 0 に設定してから、fadeIn メソッドを呼び出す必要がありました。

ここでは、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#であることは知っていますが、ほぼ同じです。これは、私が掘り起こし、2006 年以来見ていない素敵な VB です。明らかに、これを適応させて独自のフォームをフェードインおよびフェードアウトするのは簡単です。

<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 に答える