Earthquake Dialog #38
Chapter 5, Windows, Dialogs, and Frames
|
197
HACK
then shows the frame on screen. When the window is opened, the settings
will be pulled from the properties file. When the user quits the program, the
settings will be saved back to the properties file:
public static void main(String[] args) throws Exception {
Toolkit tk = Toolkit.getDefaultToolkit( );
tk.addAWTEventListener(WindowSaver.getInstance( ),
AWTEvent.WINDOW_EVENT_MASK);
final JFrame frame = new JFrame("Hack X");
frame.setName("WSTes.main");
frame.getContentPane( ).add(new JButton("a button"));
JMenuBar mb = new JMenuBar( );
JMenu menu = new JMenu("File");
menu.add(new AbstractAction("Quit") {
public void actionPerformed(ActionEvent evt) {
try {
WindowSaver.saveSettings( );
System.exit(0);
} catch (Exception ex) {
System.out.println(ex);
}
}
});
mb.add(menu);
frame.setJMenuBar(mb);
frame.pack( );
frame.show( );
}
H A C K
#38
Earthquake Dialog Hack #38
Make sure your users really know they got their password wrong.
One of the funny ways that Mac OS X uses animation in its UI is when the
user logs in. If she enters an incorrect login and/or password, the whole
login dialog shakes violently for a second, like a road sign thwacked with a
bat, or a cartoon character who has just run full-speed into a solid object
(say, a picture of a tunnel painted over a wall).
We like this effect a lot, so we thought we’d bring it to Swing. It’s a pretty
straightforward bit of animation, so we jazzed it up…with trigonometry!
Exterior Animation
Here’s an initial queston: do you want to subclass JDialog and add the ani-
mation effect to that class, or create a class that animates the shaking on
another
JDialog? I thought that subclassing would be a bad choice because
JOptionPane generates some very convenient JDialogs, and you wouldn’t
want to lose those. So, you’ll have to have another class animate your dialogs.
198
|
Chapter 5, Windows, Dialogs, and Frames
#38 Earthquake Dialog
HACK
I’ve called it DialogEarthquakeCenter because it’ll be a class that monitors
the shaking, just like seismologists do in their earthquake centers.
Obviously, the
DialogEarthquakeCenter
needs a reference to the dialog that it
will be shaking. It also needs a few other values, which I’ve set as constants:
SHAKE_DISTANCE
The maximum distance in each direction the dialog should move.
SHAKE_CYCLE
The time in milliseconds for a complete cycle: center, right, center, left,
back to center.
SHAKE_DURATION
Total time in milliseconds to shake the dialog.
SHAKE_UPDATE
How often (in milliseconds) to update the dialog’s position and repaint.
You might increase this if the CPU use is excessive, but animation
smoothness decreases with less-frequent updates.
Beyond that, all you’ll need to keep track of is where the dialog started (so
you can put it back at the end of the animation), a running clock of how far
you are into the animation, and where the dialog is located. Example 5-5
shows the code to put all this into action.
Example 5-5. A class to shake a JDialog back and forth
public class DialogEarthquakeCenter extends Object {
public static final int SHAKE_DISTANCE = 10;
public static final double SHAKE_CYCLE = 50;
public static final int SHAKE_DURATION = 1000;
public static final int SHAKE_UPDATE = 5;
private JDialog dialog;
private Point naturalLocation;
private long startTime;
private Timer shakeTimer;
private final double HALF_PI = Math.PI / 2.0;
private final double TWO_PI = Math.PI * 2.0;
public DialogEarthquakeCenter (JDialog d) {
dialog = d;
}
public void startShake( ) {
naturalLocation = dialog.getLocation( );
startTime = System.currentTimeMillis( );
shakeTimer =
new Timer(SHAKE_UPDATE,
new ActionListener( ) {
Earthquake Dialog #38
Chapter 5, Windows, Dialogs, and Frames
|
199
HACK
public void actionPerformed (ActionEvent e) {
// calculate elapsed time
long elapsed = System.currentTimeMillis( ) -
startTime;
// use sin to calculate an x-offset
double waveOffset = (elapsed % SHAKE_CYCLE) /
SHAKE_CYCLE;
double angle = waveOffset * TWO_PI;
// offset the x-location by an amount
// proportional to the sine, up to
// shake_distance
int shakenX = (int) ((Math.sin (angle) *
SHAKE_DISTANCE) +
naturalLocation.x);
dialog.setLocation (shakenX, naturalLocation.y);
dialog.repaint( );
// should we stop timer?
if (elapsed >= SHAKE_DURATION)
stopShake( );
}
}
);
shakeTimer.start( );
}
public void stopShake( ) {
shakeTimer.stop( );
dialog.setLocation (naturalLocation);
dialog.repaint( );
}
public static void main (String[] args) {
JOptionPane pane =
new JOptionPane ("You've totally screwed up your login\n" +
"Go back and do it again... and do you think\n" +
"you could remember your password this time?",
JOptionPane.ERROR_MESSAGE,
JOptionPane.OK_OPTION);
JDialog d = pane.createDialog (null, "Shakin'!");
DialogEarthquakeCenter dec = new DialogEarthquakeCenter (d);
d.pack( );
d.setModal (false);
d.setVisible(true);
dec.startShake( );
// wait (forever) for a non-null click and then quit
while (pane.getValue( ) == JOptionPane.UNINITIALIZED_VALUE ) {
try { Thread.sleep(100); }
catch (InterruptedException ie) {}
Example 5-5. A class to shake a JDialog back and forth (continued)

Get Swing Hacks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.