Hello!

I've written some swing components for which I use timing framework to make some simple animations that hopefully are going to enchance usability. What I am doing is essentially setting the bounds of JPanels for each timing event to animate something that moves and resizes. I also change transparency values during animation by using alpaComposites in the paintComponent method.

The animations look good on my dev system but lags on slower systems which the software mainly will run on.

I'm unsure about how I should optimize the performance of the animations. Does anyone now some place I can find information about this? What approaches are there to this?

Thanks!

/S

This is a topic close to my heart, but it's hard to comment without knowing more about your code - sometimes people get the threading model wrong, sometimes its as simple as re-reading image files each time the GUI updates. Can you post the relevant parts of your code?

Ok! Here some code that I think explaings how I do the animations.

First of, there is a class, AnimationPanel, which is a transparent Jpanel that contains the component that are going to be animated. In this class the following method is called to do a specific animation...

public void appear(Component[] cs) {
         Animator anim = new Animator(300, new AppearTarget(cs));
	queueAnimation(anim);
}

The components in the array cs are about to be animated from a invisible to a visible state. We create the Animator object along with the Target and place it in a queue that is waitning for for other animations to end before running the next, i.e. you can press a button rapidly several times that triggers several animations after each other.

The Animator object just calls start when it is its turn to animate and the target handles the rest.

here is the code for the AppearTarget...

private class AppearTarget extends AnimationTarget {
		public AppearTarget(Component[] cs) {
			super(cs);
		}
		@Override
		public void begin() {
			for(Component c : components) {
				if(c instanceof RoundedGlowPanel) {
					((RoundedGlowPanel) c).setTransparency(0.0f);
				}
			}	
			for(Component c : components) {
				c.setVisible(true);
			}
		}
		
		@Override
		public void end() {
			for(Component c : components) {
				if(c instanceof RoundedGlowPanel) {
					((RoundedGlowPanel) c).setTransparency(1.0f);
				}
			}	
			for(Component c : components) {
				c.setVisible(true);
			}
			super.end();
		}
		
		@Override
		public void timingEvent(float fraction) {
			double alpha = getCurvePoint(fraction);	
			for(Component c : components) {
				if(c instanceof RoundedGlowPanel) {
					((RoundedGlowPanel) c).setTransparency((float) alpha);
				}
			}
		} 
	}

The target sets some inital values at begin and for each timingEvent it sets the transparency for the RoundedGlowPanel and lastly sets the end values when end is called.

the super.end() call looks like this...

public void end() {
			synchronized (lock) {
				lock.notifyAll();
			}
		}

which makes sure that the queue that holds the animation knows when to continue to the next animation in the queue.

This is essentially the pattern I use. The rest of the targets look the same but just does different animations, like setBounds and transparency.

I profiled the program and most time is consumed in the paintComponent method of RoundedGlowPanel which I override to do custom painting like setting a clip and painting a gradient background. It uses g2d.setComposite to handle transparency (I read somewhere that this is slow).

Any ideas?

I noticed that I left out a call to repaint() at the end of the timingEvent. I don't really get how to use repaint. It is for example not needed to call it for the other animations, just for this one. The other animations call setBounds which calls repaint, so thats probablty it.

I was also thinking about buffering the animations. The idea is to make an animation each time a component changes and draw to an offscreen image. When the animation is triggered i just paint the correct image at each call to timingEvent instead of doing a lot of painting and stuff. Would that run faster?

Well, yes. If your time is being spent in the paintComponent method of RoundedGlowPanel then this is probably the gradients etc, in which case pre-rendering the images (if possible) could be a big gain.
After a quick look at the code I can't see any obvious problems, performance-wise.

What timer intervals are you using? Trying to set too high a frame rate can have a negative result if the processor can't render the graphics fast enough. Provided the frame rate is around 15fps you will get a smooth animation, but with fewer frames to render a slow CPU can keep up.

Edited 5 Years Ago by JamesCherrill: Add note on frame rate

This article has been dead for over six months. Start a new discussion instead.