Question

So basically im making a custom button.

Desired Behaviour:

When a user mouses over, then the mouseover picture will fade in.

When a user mouses off the mouseover/pressed picture will fade out.

Exceptions:

If a user mouses in, or off, while a fade animation is playing, then it will need to:

  • Instantly stop the currently playing animation
  • Start fading into the new animation from current position. Example: Lets say a user mouses over, and the mouseover animation has played, if they were to mouse off, and then mouse back on quickly while the mouseoff animation was still playing, it would not start the mouse in fade from the beginning.. but from where the mouseoff animation had stopped.
Was it helpful?

Solution

I did a similar thing to this before, and implemented it using GDI+.

The button should do two things in it's draw method.

  1. Draw the default button without any regards for transparency.
  2. Draw the mouseove image with a given alpha.

Use a BackgroundWorker to give you a smooth animation. So on mouseover start the BackgroundWorker and make it run untill Alpha reaches 1.0f. When mouse is removed from button, the worker should reduce Alpha untill it reaches 0.0f. Have a variable called fadingin so that the BackgroundWorker will understand what it should do. Your mouse in and out event should just properly set fadingin to true or false, then start the BackgroundWorker (if it's not already runnung).

The BackgroundWorkers DoWork method can look something like this:

void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) {
  long ticks1 = 0;
  long ticks2 = 0;
  double interval = (double)Stopwatch.Frequency / 60;
  while (true) {
    ticks2 = Stopwatch.GetTimestamp();
    if (ticks2 >= ticks1 + interval) {
      ticks1 = Stopwatch.GetTimestamp();

      if(_fadeIn){
        _fadeAlpha += 0.1f;
        if(_fadeAlpha > 1f){
          _fadeAlpha = 1f;
          break;
        }
      }else{
        _fadeAlpha -= 0.1f;
        if(_fadeAlpha < 0f){
          _fadeAlpha = 0f;
          break;
        }
      }
      backgroundWorker.ReportProgress(0);
    }
    Thread.Sleep(1);
  }
  backgroundWorker.ReportProgress(0);
}

The Stopwatch and loop construct here will make the animation aim for a 60fps animation.

The backgroundWorker ProgressChanged should just change the ColorMatrix to the proper alpha value, and bind the ColorMatrix to the ImageAttributes, and invalidate the control by calling Invalidate. This has to be done so that the GUI repaint is requested from the main thread, and not the BackgroundWorker thread. If you do this directly from DoWork you will get an exception if you try to modify ImageAttributes while a draw operation is taking place.

Hope this helps you to make a good smooth animation on your button.

OTHER TIPS

You need to choose one picture to be on the bottom, and one to be on top. The one on top will need its alpha value adjusted from 0 to 255 in steps to create the animation.

This MSDN forum thread details a method for the blending.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top