Simon Jensen
Simon Jensen

Reputation: 486

Using a timer and milliseconds to fade a form away but the duration is doubled

I am making my own little custom message box, essentially its just a small box showing up with a message for X amount of time, and then fades away for Y duration. What is happening tho is that the fade away takes double as long as its supposed to and I cannot figure out why. Can someone look at my code and spot why its taking double the amount of time to fade the form away than it is expected?

    //Initiate and set up the message bubble.
    public static void InitiateBubble(String displayText, Double showTime = 1000, Double fadeTime = 2000) {
        Bubble bubble = new Bubble(displayText);
        bubble.showTime = showTime;
        bubble.fadeTime = fadeTime;
        bubble.Show();
        bubble.showTimer = new Timer();
        bubble.showTimer.Interval = (int)bubble.showTime;
        bubble.showTimer.Tick += bubble.startFadeAway;
        bubble.showTimer.Start();
    }

    //Leaves some time on screen before starting to fade away
    private void startFadeAway(object sender, EventArgs e) {
        showTimer.Stop();
        fadeAwayTimer = new Timer();
        fadeAwayTimer.Interval = 10;
        fadeAwayTimer.Tick += fadeAway;
        fadeAwayTimer.Start();
    }

    //slowly fades the contorle away until it disapears.
    private void fadeAway(object sender, EventArgs e) {
        double opacity = Opacity;
        opacity -= (10 / fadeTime);
        if (opacity < 0) {
            Close();
        }
        else {
            Opacity = opacity;
        }
    }

Upvotes: 1

Views: 234

Answers (1)

Rufus L
Rufus L

Reputation: 37070

If the user sets the fade interval to 1 second (1000 milliseconds), and we set the timer interval to 1/10th of a second (100 milliseconds), then we need to fade the opacity by 10% every interval (since the interval is triggered 10 times per second). So we would set Opacity -= .1 on each iteration.

If the user sets the fade interval to 2 seconds (2000 milliseconds), and we still have the timer interval set to 1/10th of a second, then we need to fade the opacity by only 5% every interval, so we would set Opacity -= .05 on each iteration.

Seeing this relationship, we can discover that:

var amountToReduceOpacity = 1.0 / fadeTime * interval;

Note: as γηράσκω δ' αεί πολλά διδασκόμε mentioned above, the resolution on the winform timer is around 17 milliseconds, so if we set it to less than this, the fade will slow down dramatically because we will have calculated the rate for a very fast timer (meaning that we won't fade very much each iteration), but it will execute more slowly. On my machine, setting it to 50 looks just fine.

Now we can use this formula to always fade the form by the correct amount each interval. Here's a sample Form that does basically what you're doing above (note that I dropped a label and two timers on the form, and named them: lblDisplay, showTimer, and fadeTimer):

public partial class Bubble : Form
{
    private readonly double amountToReduceOpacity;
    private readonly int fadeInterval = 50; 

    // Custom form constructor takes in all three required settings
    public Bubble(string displayText, int showTime, int fadeTime)
    {
        InitializeComponent();

        lblDisplay.AutoSize = true;
        lblDisplay.Text = displayText;
        lblDisplay.Left = ClientRectangle.Width / 2 - lblDisplay.Width / 2;
        lblDisplay.Top = ClientRectangle.Height / 2 - lblDisplay.Height / 2;

        showTimer.Interval = showTime;
        fadeTimer.Interval = fadeInterval;

        amountToReduceOpacity = 1.0 / fadeTime * fadeInterval;
    }

    // The Shown event starts the first timer
    private void Bubble_Shown(object sender, EventArgs e)
    {
        showTimer.Start();
    }

    // The shownTimer starts the fadeTimer
    private void showTimer_Tick(object sender, EventArgs e)
    {
        showTimer.Stop();
        BackColor = Color.Red; // Just so we see when the fade starts
        fadeTimer.Start();
    }

    // The fade timer reduces opacity on each iteration until it's zero
    private void fadeTimer_Tick(object sender, EventArgs e)
    {
        Opacity -= amountToReduceOpacity;
        if (Opacity <= 0) Close();            
    }
}

Then on the client side we can just do something like:

private void button1_Click(object sender, EventArgs e)
{
    Bubble bubble = new Bubble("Help me, I'm Fading!", 1000, 2000);
    bubble.Show();
}

Upvotes: 2

Related Questions