This program simulates a Subway car traveling from station to station. At each stop, the doors open and close. Click on a button to make the car stop there or wait for random stops to occur.
This program is both an Applet and an Application.
Java Web Start: Launch the Subway simulation by clicking here.
Applet: Click here to view the Subway simulation as an Applet.
Download: Click here to download the jar file.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.*;
/** @author John B. Matthews; distribution per GNU Public License */
public class Subway extends JApplet {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setTitle("Subway Simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initContainer(frame);
frame.pack();
frame.setVisible(true);
}
});
}
// Common initialization for either JApplet or JFrame
private static void initContainer(Container container) {
ButtonPanel control = new ButtonPanel();
SubwayPanel subway = new SubwayPanel(control);
container.add(Box.createVerticalStrut(8), BorderLayout.NORTH);
container.add(subway, BorderLayout.CENTER);
container.add(control, BorderLayout.SOUTH);
subway.beginOperation();
}
@Override public void init() {
System.out.println("Initializing...");
initContainer(this);
}
@Override public void destroy() {
System.out.println("That's all, folks...");
}
}
class SubwayPanel extends JPanel implements ActionListener {
public static final int MAX = 8; // Max stops
private static final int DX = 4; // Initial velocity
private static final int DOOR = 100; // Preferred width
private int dx = DX;
private int xx = 0;
private int yy = 0;
private Timer timer = new Timer(40, this); // ~25 Hz
private ButtonPanel control;
private boolean loading;
public SubwayPanel(ButtonPanel control) {
this.control = control;
setPreferredSize(
new Dimension(MAX * DOOR, DOOR * 162 / 100 + 16));
}
public void beginOperation() {
timer.setInitialDelay(200);
timer.start();
timer.setInitialDelay(1000);
}
@Override public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, getWidth(), getHeight());
int width = getWidth() / MAX;
int height = getHeight();
int w2 = width / 2;
g.setColor(Color.gray);
g.fillRect(xx, yy, width, height);
g.setColor(Color.black);
g.drawRect(xx, yy, width - 1, height - 1);
if (loading) g.fillRect(xx + w2 / 2, yy, w2, height);
else g.drawLine(xx + w2, yy, xx + w2, yy + height);
}
// Handle Timer events
public void actionPerformed(ActionEvent e) {
int width = getWidth() / MAX;
int height = getHeight();
int curStop = Math.min(xx / width, MAX - 1);
boolean selected = control.getButton(curStop);
if (Math.abs(xx % width) < DX && selected) {
timer.restart();
control.clearButton(curStop);
loading = true;
} else {
xx += dx;
if (xx < 0) {
dx = -dx;
xx = 0;
}
if (xx > (MAX - 1) * width) {
dx = -dx;
xx = (MAX - 1) * width;
}
loading = false;
}
control.randomButton();
//this.repaint();
this.paintImmediately(xx - DX, yy, width + 2 * DX, height);
}
}
class ButtonPanel extends JPanel implements ActionListener {
private static final int MAX = SubwayPanel.MAX;
private static final Random rnd = new Random();
private ArrayList<JToggleButton> stops =
new ArrayList<JToggleButton>();
public ButtonPanel() {
this.setLayout(new GridLayout(1, MAX));
for (int i = 0; i < MAX; i++) {
JToggleButton tb = new JToggleButton("Stop " + (i + 1));
tb.addActionListener(this);
if ((i > 0)) tb.setSelected(rnd.nextBoolean());
stops.add(tb);
this.add(tb);
}
}
public boolean getButton(int i) {
return stops.get(i).isSelected();
}
public void clearButton(int i) {
stops.get(i).setSelected(false);
}
public void randomButton() {
if (rnd.nextGaussian() > 2.0537) // ~2%
stops.get(rnd.nextInt(MAX)).setSelected(true);
}
public void actionPerformed(ActionEvent e) {
JToggleButton button = (JToggleButton)e.getSource();
button.setSelected(true);
}
}
Copyright © 2008 John B. Matthews. Distributed under the terms of the GPL