Mega Code Archive

 
Categories / Java / Threads
 

Swing Type Tester 10

/* Java Threads, 3rd Edition By Scott Oaks, Henry Wong 3rd Edition September 2004  ISBN: 0-596-00782-5 */ import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Random; import java.util.Vector; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class SwingTypeTester10 extends JFrame implements CharacterSource {   protected RandomCharacterGenerator producer;   private AnimatedCharacterDisplayCanvas displayCanvas;   private CharacterDisplayCanvas feedbackCanvas;   private JButton quitButton;   private JButton startButton;   private JButton stopButton;   private CharacterEventHandler handler;   private ScoreLabel score;   public SwingTypeTester10() {     initComponents();   }   private void initComponents() {     handler = new CharacterEventHandler();     producer = new RandomCharacterGenerator();     producer.setDone(true);     producer.start();     displayCanvas = new AnimatedCharacterDisplayCanvas(producer);     feedbackCanvas = new CharacterDisplayCanvas(this);     quitButton = new JButton();     startButton = new JButton();     stopButton = new JButton();     score = new ScoreLabel(producer, this);     Container pane = getContentPane();     JPanel p1 = new JPanel();     p1.setLayout(new BoxLayout(p1, BoxLayout.PAGE_AXIS));     p1.add(displayCanvas);     p1.add(feedbackCanvas);     JPanel p2 = new JPanel();     score.setText("      ");     score.setFont(new Font("MONOSPACED", Font.BOLD, 30));     p2.add(score);     startButton.setText("Start");     p2.add(startButton);     stopButton.setText("Stop");     stopButton.setEnabled(false);     p2.add(stopButton);     quitButton.setText("Quit");     p2.add(quitButton);     p1.add(p2);     pane.add(p1, BorderLayout.NORTH);     pack();     addWindowListener(new WindowAdapter() {       public void windowClosing(WindowEvent evt) {         quit();       }     });     feedbackCanvas.addKeyListener(new KeyAdapter() {       public void keyPressed(KeyEvent ke) {         char c = ke.getKeyChar();         if (c != KeyEvent.CHAR_UNDEFINED)           newCharacter((int) c);       }     });     startButton.addActionListener(new ActionListener() {       public void actionPerformed(ActionEvent evt) {         displayCanvas.setDone(false);         producer.setDone(false);         score.resetScore();         startButton.setEnabled(false);         stopButton.setEnabled(true);         feedbackCanvas.setEnabled(true);         feedbackCanvas.requestFocus();       }     });     stopButton.addActionListener(new ActionListener() {       public void actionPerformed(ActionEvent evt) {         startButton.setEnabled(true);         stopButton.setEnabled(false);         producer.setDone(true);         displayCanvas.setDone(true);         feedbackCanvas.setEnabled(false);       }     });     quitButton.addActionListener(new ActionListener() {       public void actionPerformed(ActionEvent evt) {         quit();       }     });   }   private void quit() {     System.exit(0);   }   public void addCharacterListener(CharacterListener cl) {     handler.addCharacterListener(cl);   }   public void removeCharacterListener(CharacterListener cl) {     handler.removeCharacterListener(cl);   }   public void newCharacter(int c) {     handler.fireNewCharacter(this, c);   }   public void nextCharacter() {     throw new IllegalStateException("We don't produce on demand");   }   public static void main(String args[]) {     new SwingTypeTester10().show();   } } class ScoreLabel extends JLabel implements CharacterListener {   private volatile int score = 0;   private int char2type = -1;   private CharacterSource generator = null, typist = null;   private Lock scoreLock = new ReentrantLock();   public ScoreLabel(CharacterSource generator, CharacterSource typist) {     this.generator = generator;     this.typist = typist;     if (generator != null)       generator.addCharacterListener(this);     if (typist != null)       typist.addCharacterListener(this);   }   public ScoreLabel() {     this(null, null);   }   public void resetGenerator(CharacterSource newGenerator) {     try {       scoreLock.lock();       if (generator != null)         generator.removeCharacterListener(this);       generator = newGenerator;       if (generator != null)         generator.addCharacterListener(this);     } finally {       scoreLock.unlock();     }   }   public void resetTypist(CharacterSource newTypist) {     try {       scoreLock.lock();       if (typist != null)         typist.removeCharacterListener(this);       typist = newTypist;       if (typist != null)         typist.addCharacterListener(this);     } finally {       scoreLock.unlock();     }   }   public void resetScore() {     try {       scoreLock.lock();       score = 0;       char2type = -1;       setScore();     } finally {       scoreLock.unlock();     }   }   private void setScore() {     SwingUtilities.invokeLater(new Runnable() {       public void run() {         setText(Integer.toString(score));       }     });   }   public void newCharacter(CharacterEvent ce) {     scoreLock.lock();     try {       if (ce.source == generator) {         if (char2type != -1) {           score--;           setScore();         }         char2type = ce.character;       } else {         if (char2type != ce.character) {           score--;         } else {           score++;           char2type = -1;         }       }       setScore();     } finally {       scoreLock.unlock();     }   } } class RandomCharacterGenerator extends Thread implements CharacterSource {   private static char[] chars;   private static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789";   static {     chars = charArray.toCharArray();   }   private Random random;   private CharacterEventHandler handler;   private boolean done = true;   private Lock lock = new ReentrantLock();   private Condition cv = lock.newCondition();   public RandomCharacterGenerator() {     random = new Random();     handler = new CharacterEventHandler();   }   public int getPauseTime(int minTime, int maxTime) {     return (int) (minTime + ((maxTime - minTime) * random.nextDouble()));   }   public int getPauseTime() {     return getPauseTime(2000, 5500);   }   public void addCharacterListener(CharacterListener cl) {     handler.addCharacterListener(cl);   }   public void removeCharacterListener(CharacterListener cl) {     handler.removeCharacterListener(cl);   }   public void nextCharacter() {     handler.fireNewCharacter(this,         (int) chars[random.nextInt(chars.length)]);   }   public void run() {     try {       lock.lock();       while (true) {         try {           if (done) {             cv.await();           } else {             nextCharacter();             cv.await(getPauseTime(), TimeUnit.MILLISECONDS);           }         } catch (InterruptedException ie) {           return;         }       }     } finally {       lock.unlock();     }   }   public void setDone(boolean b) {     try {       lock.lock();       done = b;       if (!done)         cv.signal();     } finally {       lock.unlock();     }   } } interface CharacterListener {   public void newCharacter(CharacterEvent ce); } interface CharacterSource {   public void addCharacterListener(CharacterListener cl);   public void removeCharacterListener(CharacterListener cl);   public void nextCharacter(); } class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements     CharacterListener, Runnable {   private volatile boolean done = false;   private int curX;   private Lock lock = new ReentrantLock();   private Condition cv = lock.newCondition();   private Thread timer = null;   public AnimatedCharacterDisplayCanvas(CharacterSource cs) {     super(cs);   }   public synchronized void newCharacter(CharacterEvent ce) {     curX = 0;     tmpChar[0] = (char) ce.character;     repaint();   }   public synchronized void paintComponent(Graphics gc) {     if (tmpChar[0] == 0)       return;     Dimension d = getSize();     int charWidth = fm.charWidth(tmpChar[0]);     gc.clearRect(0, 0, d.width, d.height);     gc.drawChars(tmpChar, 0, 1, curX++, fontHeight);     if (curX > d.width - charWidth)       curX = 0;   }   public void run() {     try {       lock.lock();       while (true) {         try {           if (done) {             cv.await();           } else {             repaint();             cv.await(100, TimeUnit.MILLISECONDS);           }         } catch (InterruptedException ie) {           return;         }       }     } finally {       lock.unlock();     }   }   public void setDone(boolean b) {     try {       lock.lock();       done = b;       if (timer == null) {         timer = new Thread(this);         timer.start();       }       if (!done)         cv.signal();     } finally {       lock.unlock();     }   } } class CharacterDisplayCanvas extends JComponent implements CharacterListener {   protected FontMetrics fm;   protected char[] tmpChar = new char[1];   protected int fontHeight;   public CharacterDisplayCanvas(CharacterSource cs) {     setFont(new Font("Monospaced", Font.BOLD, 18));     fm = Toolkit.getDefaultToolkit().getFontMetrics(getFont());     fontHeight = fm.getHeight();     cs.addCharacterListener(this);   }   public void setCharacterListener(CharacterSource cs) {     cs.addCharacterListener(this);   }   public Dimension preferredSize() {     return new Dimension(fm.getMaxAscent() + 10, fm.getMaxAdvance() + 10);   }   public synchronized void newCharacter(CharacterEvent ce) {     tmpChar[0] = (char) ce.character;     repaint();   }   protected synchronized void paintComponent(Graphics gc) {     Dimension d = getSize();     gc.clearRect(0, 0, d.width, d.height);     if (tmpChar[0] == 0)       return;     int charWidth = fm.charWidth((int) tmpChar[0]);     gc.drawChars(tmpChar, 0, 1, (d.width - charWidth) / 2, fontHeight);   } } class CharacterEvent {   public CharacterSource source;   public int character;   public CharacterEvent(CharacterSource cs, int c) {     source = cs;     character = c;   } } class CharacterEventHandler {   private Vector listeners = new Vector();   public void addCharacterListener(CharacterListener cl) {     listeners.add(cl);   }   public void removeCharacterListener(CharacterListener cl) {     listeners.remove(cl);   }   public void fireNewCharacter(CharacterSource source, int c) {     CharacterEvent ce = new CharacterEvent(source, c);     CharacterListener[] cl = (CharacterListener[]) listeners         .toArray(new CharacterListener[0]);     for (int i = 0; i < cl.length; i++)       cl[i].newCharacter(ce);   } }