/** * Copyright (c) 2006, Sun Microsystems, Inc * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the TimingFramework project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * ButtonAnimation * * This class demonstrates the functionality of the Timing Framework library. * It uses a GUI that allows the user to enter various settings of the * animation and then start it. The animation consists of two elements: * a button called "Animating Button" (which demonstrates the property-setting * capabilities of the framework) and a string called "fraction" that * demonstrates the more basic interaction between the TimingController and * TimingTarget interface. */ package org.jdesktop.animation.timing.examples; import org.jdesktop.animation.timing.interpolation.KeyFrames; import org.jdesktop.animation.timing.interpolation.KeyTimes; import org.jdesktop.animation.timing.interpolation.KeyValues; import org.jdesktop.animation.timing.interpolation.PropertySetter; import org.jdesktop.animation.timing.Animator; import org.jdesktop.animation.timing.TimingTarget; import java.awt.*; import java.awt.event.*; import java.text.*; import javax.swing.*; import javax.swing.border.*; import org.jdesktop.animation.timing.interpolation.DiscreteInterpolator; import org.jdesktop.animation.timing.interpolation.Interpolator; import org.jdesktop.animation.timing.interpolation.LinearInterpolator; import org.jdesktop.animation.timing.interpolation.SplineInterpolator; /** * This class is the heart of the demo; in its actionPerformed() method it * takes the information from the GUI controls, sets up the animation * according to those settings, and starts the animation. * It also handles the tedious work of setting up the rather * involved GUI. */ class ControlPanel extends JPanel implements ActionListener { NumberFormat intFormat; NumberFormat doubleFormat; JFormattedTextField beginField; JFormattedTextField durationField; JFormattedTextField resolutionField; JFormattedTextField repeatCountField; JFormattedTextField initialFractionField; JRadioButton loopButton, reverseButton; JRadioButton holdButton, resetButton; JRadioButton forwardButton, backwardButton; JRadioButton linearButton, discreteButton, nonlinearButton; JRadioButton twoButton, threeButton, fourButton; JButton goButton, stopButton, pauseButton, resumeButton; JFormattedTextField time[] = new JFormattedTextField[4]; JFormattedTextField valueX[] = new JFormattedTextField[4]; JFormattedTextField valueY[] = new JFormattedTextField[4]; JFormattedTextField splineX0[] = new JFormattedTextField[4]; JFormattedTextField splineY0[] = new JFormattedTextField[4]; JFormattedTextField splineX1[] = new JFormattedTextField[4]; JFormattedTextField splineY1[] = new JFormattedTextField[4]; JFormattedTextField accelerationField; JFormattedTextField decelerationField; Animator animation = null; AnimationView animationView; // We will pass this into Animation // so that the animation fraction can // can be passed into AnimationView // during the animation. /** * "Go" button pressed: get the values from the controls and * getInstance/start the animation. This is the heart of the whole * demo, where we getInstance and run a Animator based on the * current state of the GUI. */ public void actionPerformed(ActionEvent ae) { // First, check to see whether someone is pausing/resuming/stopping the // animation if (animation != null) { if (ae.getSource().equals(pauseButton)) { animation.pause(); return; } else if (ae.getSource().equals(resumeButton)) { animation.resume(); return; } else if (ae.getSource().equals(pauseButton)) { animation.stop(); return; } } // If we are already running an animation, stop it pending // a restart with the new control values if (animation != null && animation.isRunning()) { animation.stop(); } // First, distinguish between a toggle of the number of // keyframes and a click on the GO button if (!ae.getSource().equals(goButton)) { enableTextFields(twoButton.isSelected() ? 2 : (threeButton.isSelected() ? 3 : 4)); return; } // Must be a GO action; setup and start the animation // First, set up the Cycle and Envelope needed by // Animator int begin = getFieldValueAsInt(beginField); int duration = getFieldValueAsInt(durationField); int resolution = getFieldValueAsInt(resolutionField); double repeatCount = getFieldValueAsDouble(repeatCountField); double initialFraction = getFieldValueAsDouble(initialFractionField); Animator.Direction direction = forwardButton.isSelected() ? Animator.Direction.FORWARD : Animator.Direction.BACKWARD; Animator.RepeatBehavior repeatBehavior = reverseButton.isSelected() ? Animator.RepeatBehavior.REVERSE : Animator.RepeatBehavior.LOOP; Animator.EndBehavior behavior = (holdButton.isSelected()) ? Animator.EndBehavior.HOLD : Animator.EndBehavior.RESET; // Next, set up the property setter information based on the // keyframes-related widgets JComponent animatingComponent = animationView.getAnimatingComponent(); int numKeyframes = twoButton.isSelected() ? 2 : (threeButton.isSelected() ? 3 : 4); float times[] = new float[numKeyframes]; Point points[] = new Point[numKeyframes]; Interpolator interpolators[] = null; if (nonlinearButton.isSelected()) { interpolators = new Interpolator[numKeyframes-1]; for (int i = 0; i < numKeyframes - 1; ++i) { interpolators[i] = new SplineInterpolator( (float)getFieldValueAsDouble(splineX0[i]), (float)getFieldValueAsDouble(splineY0[i]), (float)getFieldValueAsDouble(splineX1[i]), (float)getFieldValueAsDouble(splineY1[i])); } } for (int i = 0; i < numKeyframes; ++i) { times[i] = (float)getFieldValueAsDouble(time[i]); points[i] = new Point(getFieldValueAsInt(valueX[i]), getFieldValueAsInt(valueY[i])); } KeyTimes keyTimes = new KeyTimes(times); KeyValues keyValues = KeyValues.create(points); //KeySplines keySplines = (interpolationType == InterpolationType.NONLINEAR) ? // new KeySplines(splines) : null; KeyFrames keyFrames; if (nonlinearButton.isSelected()) { keyFrames = new KeyFrames(keyValues, keyTimes, interpolators); } else if (discreteButton.isSelected()) { keyFrames = new KeyFrames(keyValues, keyTimes, DiscreteInterpolator.getInstance()); } else { keyFrames = new KeyFrames(keyValues, keyTimes, (Interpolator)null); } // Create the Animator with a PropertySetter as // the TimingTarget; this will do the work of setting the property // specified above animation = new Animator(duration, repeatCount, repeatBehavior, new PropertySetter(animatingComponent, "location", keyFrames)); animation.setResolution(resolution); animation.setStartDelay(begin); animation.setEndBehavior(behavior); animation.setStartFraction((float)initialFraction); animation.setStartDirection(direction); // Now add another TimingTarget to the animation; this will track // and display the animation fraction animation.addTarget(animationView); animationView.setTimer(animation); // Vary the acceleration/deceleration values appropriately float acceleration = (float)getFieldValueAsDouble(accelerationField); float deceleration = (float)getFieldValueAsDouble(decelerationField); animation.setAcceleration(acceleration); animation.setDeceleration(deceleration); // Finally: start the animation animation.start(); } // // GUI Setup // The rest of the methods in this class are all about setting up and // running the GUI of the control panel // private void setupCycleGUI() { JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); textPanel.add(new JLabel("Duration (ms)"), new GridBagConstraints(0, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); durationField = new JFormattedTextField(intFormat); durationField.setValue(1000); textPanel.add(durationField, new GridBagConstraints(2, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.add(new JLabel("Resolution (ms)"), new GridBagConstraints(4, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); resolutionField = new JFormattedTextField(intFormat); resolutionField.setValue(0); textPanel.add(resolutionField, new GridBagConstraints(6, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.add(new JLabel("Initial Fraction (0-1)"), new GridBagConstraints(0, 1, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); initialFractionField = new JFormattedTextField(doubleFormat); initialFractionField.setValue(0); textPanel.add(initialFractionField, new GridBagConstraints(2, 1, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.add(new JLabel("Direction"), new GridBagConstraints(4, 1, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); forwardButton = new JRadioButton("Forward", true); backwardButton = new JRadioButton("Backward"); ButtonGroup group = new ButtonGroup(); group.add(forwardButton); group.add(backwardButton); JPanel buttonPanel = new JPanel(); buttonPanel.add(forwardButton); buttonPanel.add(backwardButton); textPanel.add(buttonPanel, new GridBagConstraints(6, 1, 2, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); textPanel.setBorder(new TitledBorder("Cycle")); add(textPanel, new GridBagConstraints(0, 0, 8, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } private void setupEnvelopeGUI() { JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); textPanel.add(new JLabel("Time to Begin (ms):"), new GridBagConstraints(0, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); beginField = new JFormattedTextField(intFormat); beginField.setValue(0); textPanel.add(beginField, new GridBagConstraints(2, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.add(new JLabel("RepeatCount:"), new GridBagConstraints(4, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); repeatCountField = new JFormattedTextField(doubleFormat); repeatCountField.setValue(2); textPanel.add(repeatCountField, new GridBagConstraints(6, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // Direction radio buttons loopButton = new JRadioButton("Loop", true); reverseButton = new JRadioButton("Reverse"); ButtonGroup group = new ButtonGroup(); group.add(loopButton); group.add(reverseButton); JPanel buttonPanel = new JPanel(); buttonPanel.setBorder(new TitledBorder("Repeat Behavior")); buttonPanel.add(loopButton); buttonPanel.add(reverseButton); textPanel.add(buttonPanel, new GridBagConstraints(0, 1, 4, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // EndBehavior radio buttons holdButton = new JRadioButton("Hold", true); resetButton = new JRadioButton("Reset"); group = new ButtonGroup(); group.add(holdButton); group.add(resetButton); buttonPanel = new JPanel(); buttonPanel.setBorder(new TitledBorder("End Behavior")); buttonPanel.add(holdButton); buttonPanel.add(resetButton); textPanel.add(buttonPanel, new GridBagConstraints(4, 1, 4, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); textPanel.setBorder(new TitledBorder("Envelope")); add(textPanel, new GridBagConstraints(0, 1, 8, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } private void setupPropertySetterGUI() { // Interpolation radio buttons linearButton = new JRadioButton("Linear", true); discreteButton = new JRadioButton("Discrete"); nonlinearButton = new JRadioButton("Nonlinear"); ButtonGroup group = new ButtonGroup(); group.add(linearButton); group.add(discreteButton); group.add(nonlinearButton); JPanel buttonPanel = new JPanel(); buttonPanel.setBorder(new TitledBorder("Interpolation")); buttonPanel.add(linearButton); buttonPanel.add(discreteButton); buttonPanel.add(nonlinearButton); linearButton.addActionListener(this); discreteButton.addActionListener(this); nonlinearButton.addActionListener(this); add(buttonPanel, new GridBagConstraints(0, 3, 5, 1, .5, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); // Num keyframes radio buttons twoButton = new JRadioButton("2", true); threeButton = new JRadioButton("3"); fourButton = new JRadioButton("4"); group = new ButtonGroup(); group.add(twoButton); group.add(threeButton); group.add(fourButton); buttonPanel = new JPanel(); buttonPanel.setBorder(new TitledBorder("Number of key frames")); buttonPanel.add(twoButton); buttonPanel.add(threeButton); buttonPanel.add(fourButton); twoButton.addActionListener(this); threeButton.addActionListener(this); fourButton.addActionListener(this); add(buttonPanel, new GridBagConstraints(5, 3, 3, 1, .5, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); setupKeyTimesGUI(); setupKeyValuesGUI(); setupKeySplinesGUI(); } private void setupKeyTimesGUI() { JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); for (int i = 0; i < 4; ++i) { textPanel.add(new JLabel("time" + i + ":"), new GridBagConstraints(0, i, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); time[i] = new JFormattedTextField(doubleFormat); if (i == 0) { time[i].setValue(0); } else { time[i].setValue(1); } textPanel.add(time[i], new GridBagConstraints(1, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); } textPanel.setBorder(new TitledBorder("KeyTimes (0-1)")); add(textPanel, new GridBagConstraints(0, 4, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } private void setupKeyValuesGUI() { JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); for (int i = 0; i < 4; ++i) { textPanel.add(new JLabel("(x, y)" + i + ":"), new GridBagConstraints(0, i, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); // X valueX[i] = new JFormattedTextField(intFormat); valueX[i].setValue(0); textPanel.add(valueX[i], new GridBagConstraints(1, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // Y valueY[i] = new JFormattedTextField(intFormat); if (i == 0) { valueY[i].setValue(0); } else { valueY[i].setValue(190); } textPanel.add(valueY[i], new GridBagConstraints(2, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); } textPanel.setBorder(new TitledBorder("KeyValues")); add(textPanel, new GridBagConstraints(1, 4, 2, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } private void setupKeySplinesGUI() { JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); for (int i = 0; i < 3; ++i) { textPanel.add(new JLabel("Spline" + i + ":"), new GridBagConstraints(0, i, 1, 1, 0, 0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); // X0 splineX0[i] = new JFormattedTextField(doubleFormat); splineX0[i].setValue(0); textPanel.add(splineX0[i], new GridBagConstraints(1, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // Y0 splineY0[i] = new JFormattedTextField(doubleFormat); splineY0[i].setValue(0); textPanel.add(splineY0[i], new GridBagConstraints(2, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // X1 splineX1[i] = new JFormattedTextField(doubleFormat); splineX1[i].setValue(1); textPanel.add(splineX1[i], new GridBagConstraints(3, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); // Y1 splineY1[i] = new JFormattedTextField(doubleFormat); splineY1[i].setValue(1); textPanel.add(splineY1[i], new GridBagConstraints(4, i, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); } textPanel.setBorder(new TitledBorder("KeySplines (0-1)")); add(textPanel, new GridBagConstraints(3, 4, 5, 2, .5, 0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } private void setupAccelerationGUI() { // Acceleration/Deceleration JPanel textPanel = new JPanel(); textPanel.setLayout(new GridBagLayout()); textPanel.add(new JLabel("acceleration"), new GridBagConstraints(0, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); accelerationField = new JFormattedTextField(doubleFormat); accelerationField.setValue(0); textPanel.add(accelerationField, new GridBagConstraints(2, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.add(new JLabel("deceleration"), new GridBagConstraints(3, 0, 2, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 0, 0), 0, 0)); decelerationField = new JFormattedTextField(doubleFormat); decelerationField.setValue(0); textPanel.add(decelerationField, new GridBagConstraints(5, 0, 1, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); textPanel.setBorder(new TitledBorder("Acceleration (acc + dec <= 1)")); add(textPanel, new GridBagConstraints(0, 5, 5, 1, .5, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0)); } /** * Set up the Go/Stop/Pause/Resume buttons */ private void setupActionsGUI() { JPanel buttonPanel = new JPanel(); add(buttonPanel, new GridBagConstraints(5, 5, 3, 1, .5, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(5, 5, 0, 5), 0, 0)); buttonPanel.setBorder(new TitledBorder("Actions")); buttonPanel.setLayout(new GridBagLayout()); pauseButton = new JButton("Pause"); resumeButton = new JButton("Resume"); stopButton = new JButton("Stop"); goButton = new JButton("Go"); pauseButton.addActionListener(this); resumeButton.addActionListener(this); stopButton.addActionListener(this); goButton.addActionListener(this); buttonPanel.add(pauseButton, new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); buttonPanel.add(resumeButton, new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); buttonPanel.add(stopButton, new GridBagConstraints(1, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); buttonPanel.add(goButton, new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 0), 0, 0)); } /** * Sets up the GUI for all of the text fields and radio buttons * that control the animation. There is some attempt to group the * controls logically (Cycle, Envelope, etc.). */ public ControlPanel(AnimationView animationView) { this.animationView = animationView; setLayout(new GridBagLayout()); intFormat = NumberFormat.getNumberInstance(); intFormat.setParseIntegerOnly(true); doubleFormat = NumberFormat.getNumberInstance(); setupCycleGUI(); setupEnvelopeGUI(); setupPropertySetterGUI(); setupAccelerationGUI(); setupActionsGUI(); // Animation View JPanel panel = new JPanel(new BorderLayout()); panel.add(animationView); TitledBorder animationBorder = new TitledBorder("Animation"); animationBorder.setTitleFont(panel.getFont().deriveFont(18f)); animationBorder.setTitleJustification(TitledBorder.CENTER); panel.setBorder(animationBorder); add(panel, new GridBagConstraints(0, 6, 8, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0)); // Set text fields to proper editable state enableTextFields(2); } /** * Utility method to retrieve textfield value as integer */ private int getFieldValueAsInt(JTextField field) { String text = field.getText(); int returnValue = 0; try { returnValue = NumberFormat.getNumberInstance().parse(text).intValue(); } catch (Exception e) { System.out.println("Number formation exception: " + e); } return returnValue; } /** * Utility method to retrieve textfield value as double */ private double getFieldValueAsDouble(JTextField field) { String text = field.getText(); double returnValue = 0; try { returnValue = NumberFormat.getNumberInstance().parse(text).doubleValue(); } catch (Exception e) { System.out.println("Number formation exception: " + e); } return returnValue; } /** * This method enables/disables the text fields for KeyTimes, KeyValues, * and KeySplines based on the current setting in the "Number of * key frames" panel plus the setting of the Interpolation buttons */ private void enableTextFields(int numKeyFrames) { // Disable appropriate time, value, spline widgets // First, set splines to default (non-editable) state for (int i = 0; i < 3; ++i) { splineX0[i].setEditable(false); splineY0[i].setEditable(false); splineX1[i].setEditable(false); splineY1[i].setEditable(false); } float timeFraction = 1.0f / (numKeyFrames - 1); for (int i = 0; i < numKeyFrames; ++i) { time[i].setEditable(true); time[i].setValue(timeFraction * i); valueX[i].setEditable(true); valueY[i].setEditable(true); if (i < (numKeyFrames - 1) && nonlinearButton.isSelected()) { splineX0[i].setEditable(true); splineY0[i].setEditable(true); splineX1[i].setEditable(true); splineY1[i].setEditable(true); } } for (int i = numKeyFrames; i < 4; ++i) { time[i].setEditable(false); valueX[i].setEditable(false); valueY[i].setEditable(false); splineX0[i-1].setEditable(false); splineY0[i-1].setEditable(false); splineX1[i-1].setEditable(false); splineY1[i-1].setEditable(false); } } } /** * The canvas where the animation is drawn. Most of the work is done * by the superclass (simply drawing the animating button at its proper * location), but we override paintComponent() in order to display the * animation fraction amount in the view. */ class AnimationView extends JComponent implements TimingTarget { JButton button = new JButton("Animating Button"); float currentFraction; Animator timer = null; public AnimationView() { try { add(button); button.setBounds(0, 0, 150, 20); } catch (Exception e) { System.out.println("Problem adding button: " + e); } } public void setTimer(Animator timer) { this.timer = timer; } JComponent getAnimatingComponent() { return button; } // // TimingTarget methods // We use these just to set the value of currentFraction, which will // be displayed in the AnimationView upon repaint // public void begin() { currentFraction = 0; } public void end() { currentFraction = 1; } public void repeat() {} public void timingEvent(float fraction) { currentFraction = fraction; int x = getWidth() - 100; int y = 0; paintImmediately(x, y, 100, 10); } /** * Draws the image in the proper location according to where it * is in the animation cycle (given by currentFraction). */ public void paintComponent(Graphics g) { g.drawString("fraction = " + currentFraction, getWidth() - 100, 10); } } /** * Main class that starts it off. This creates the view where * the animation is drawn (AnimationView) and the GUI that * controls the aimation (ControlPanel). */ public class ButtonAnimation { /** * Creates the window and sub-panels and makes it all visible */ private static void createAndShowGUI() { UIManager.put("swing.boldMetal", Boolean.FALSE); JFrame f = new JFrame("Timing Demo"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setLayout(new BorderLayout()); f.setSize(500, 800); AnimationView animationView = new AnimationView(); ControlPanel controlPanel = new ControlPanel(animationView); f.add(controlPanel, BorderLayout.CENTER); f.setVisible(true); } public static void main(String[] args) { // Need to do GUI stuff like making the JFrame visible on the // Event Dispatch Thread; do this via invokeLater() Runnable doCreateAndShowGUI = new Runnable() { public void run() { createAndShowGUI(); } }; SwingUtilities.invokeLater(doCreateAndShowGUI); } }