import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; public class DisplayFrame extends JFrame implements ActionListener, ChangeListener, Runnable { // Action commands final static String CMD_STOP = "stop"; final static String CMD_FWD = "fwd"; final static String CMD_REV = "rev"; // GUI components JPanel displayPanel; JButton revButton; JButton stopButton; JButton fwdButton; JLabel stateLabel; JSlider ndtSlider; // Thread sync components Lock runLock = new Lock(); Lock displayLock = new Lock(); Thread thread; // Simulation components sim s; int ndt; boolean direction; public DisplayFrame(sim sim_s) { s = sim_s; ndt = 50; direction = true; setTitle("Schroedinger Simulation"); setDefaultCloseOperation(DISPOSE_ON_CLOSE); addWindowListener(new WindowAdapter () { public void windowClosed(WindowEvent e) { thread.interrupt(); } }); // Create GUI components displayPanel = new JPanel() { public void paintComponent(Graphics g) { super.paintComponent(g); Dimension d = getSize(); s.render(g, d); displayLock.enable(); } }; displayPanel.setPreferredSize(new Dimension(640, 480)); ndtSlider = new JSlider(0, 1000, ndt); ndtSlider.setMinorTickSpacing(50); ndtSlider.setMajorTickSpacing(200); ndtSlider.createStandardLabels(200); ndtSlider.setPaintTicks(true); ndtSlider.setPaintLabels(true); ndtSlider.addChangeListener(this); revButton = new JButton("<<"); revButton.setActionCommand(CMD_REV); revButton.addActionListener(this); stopButton = new JButton("Stop"); stopButton.setActionCommand(CMD_STOP); stopButton.addActionListener(this); fwdButton = new JButton(">>"); fwdButton.setActionCommand(CMD_FWD); fwdButton.addActionListener(this); stateLabel = new JLabel("state: Stopped"); // Put it all together Container contents = getContentPane(); contents.add(displayPanel, BorderLayout.NORTH); JPanel p = new JPanel(); p.add(revButton); p.add(stopButton); p.add(fwdButton); contents.add(p, BorderLayout.WEST); contents.add(stateLabel, BorderLayout.CENTER); contents.add(ndtSlider, BorderLayout.SOUTH); thread = new Thread(this); thread.start(); } public void run() { try { while (true) { runLock.grab(); displayLock.grab(); displayLock.disable(); s.step(direction, ndt); displayPanel.repaint(); } } catch (Exception e) { System.out.print("run(): "); System.out.println(e); } } public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals(CMD_STOP)) { runLock.disable(); stateLabel.setText("Stopped"); } else if (cmd.equals(CMD_FWD)) { direction = true; runLock.enable(); stateLabel.setText("Running forwards"); } else if (cmd.equals(CMD_REV)) { direction = false; runLock.enable(); stateLabel.setText("Running in reverse"); } } public void stateChanged(ChangeEvent e) { ndt = ndtSlider.getValue(); } class Lock extends Object { boolean enabled = false; synchronized public void grab() throws InterruptedException { while (!enabled) { wait(); } } synchronized public void enable() { enabled = true; notifyAll(); } public void disable() { enabled = false; } } }