import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; /** * A GUI application with start and stop buttons * that control a small animation of a moving block * * @author Sharon Tuttle * @version 2015-10-21 */ public class BlockThread1 { /** * creates a BlockThread1Frame * * @param args not used here */ public static void main(String args[]) { EventQueue.invokeLater( new Runnable() { public void run() { BlockThread1Frame mainFrame = new BlockThread1Frame(); mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); mainFrame.setVisible(true); } }); } } /** * A frame that passes on its size to the JPanel * subclass instance it adds to itself */ class BlockThread1Frame extends JFrame { // data fields private final static int DEFAULT_WIDTH = 450; private final static int DEFAULT_HEIGHT = 200; /** * constructs a BlockThread1Frame instance */ public BlockThread1Frame() { this.setTitle("BlockThread1"); this.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // add BlockThread1 panel to frame BlockThread1Panel panel = new BlockThread1Panel(DEFAULT_WIDTH, DEFAULT_HEIGHT); this.add(panel); } } /** * a JPanel subclass has a subpanel with an animation * that can be started and stopped */ class BlockThread1Panel extends JPanel { // data fields private final static Font DISPLAY_FONT = new Font("Dialog", Font.PLAIN, 20); // info about the block to be animated private int blockX; private int blockY; private static final int BLOCK_WIDTH = 40; private static final int BLOCK_HEIGHT = 20; private static final Color BLOCK_COLOR = Color.RED; // info about the panel's rough size private int displayWidth; private int displayHeight; private Thread paintThread; private PaintItRunnable myPaintIt; /** * set up display parameters and a Runnable instance * for eventually moving a block around * * @param width desired display width, in pixels * @param height desired display height, in pixels * */ public BlockThread1Panel(int width, int height) { this.setLayout(new BorderLayout()); // I am putting buttons in the bottom of this // panel -- so the display sub-panel is going // to be shorter than the frame's height // (hmm; three times the buttons' DISPLAY_FONT size, maybe?) BlockPanel aBlockPanel = new BlockPanel( width, height - (3 * DISPLAY_FONT.getSize())); this.add(aBlockPanel, BorderLayout.CENTER); // putting buttons to start and stop the animation // thread in the bottom/page_end of the panel JPanel buttonPanel = new JPanel(); JButton beginButton = new JButton("Begin"); beginButton.setFont(DISPLAY_FONT); beginButton.addActionListener(new BeginThread()); buttonPanel.add(beginButton); JButton endButton = new JButton("End"); endButton.setFont(DISPLAY_FONT); endButton.addActionListener(new EndThread()); buttonPanel.add(endButton); this.add(buttonPanel, BorderLayout.PAGE_END); } /** * this subpanel is the one that will actually have * a block painted on it */ private class BlockPanel extends JPanel { /** * construct a new BlockPanel * * @param width new BlockPanel's desired displayWidth * @param height new BlockPanel's desired displayHeight */ public BlockPanel(int width, int height) { displayWidth = width; displayHeight = height; // start out the block in about the middle of the screen blockX = (int) (displayWidth / 2.0); blockY = (int) (displayHeight / 2.0); myPaintIt = new PaintItRunnable(); // I am not creating paintThread yet -- want to wait // until begin button is pushed (so I can // recreate it more than once } /** * paint/draw a block on this panel * * @param g the Graphics object with the needed settings */ public void paintComponent(Graphics g) { // calling parent JPanel's version of paintComponent // to take care of painting the background, etc. super.paintComponent(g); // painting a red block at the current blockX, blockY // values g.setColor(BLOCK_COLOR); g.fillRect(blockX, blockY, BLOCK_WIDTH, BLOCK_HEIGHT); } } /** * this is to move the block across the BlockPanel */ private class PaintItRunnable implements Runnable { /** * "move" the block across the BlockPanel */ public void run() { boolean finished = false; // until interrupted, "move" the block right 5 pixels about // every .1 second until run out of panel -- then start // back at the left side while (!finished) { try { // go right 5 pixels, unless have gone beyond // the right side of the panel - then start // back at the left side if (blockX < displayWidth) { blockX += 5; } else { blockX = 0; } repaint(); // notice: we are sleeping in this "new" // Thread, not the event dispatch thread Thread.sleep(100); } catch (InterruptedException exc) { finished = true; } } } } /** * start up a new animation thread */ private class BeginThread implements ActionListener { /** * if there is currently not an animation thread, * create one and start it up * * @param event click of the Begin button */ public void actionPerformed(ActionEvent event) { // only create a new animation thread if there // is not one right now if (paintThread == null) { paintThread = new Thread(myPaintIt); paintThread.start(); } } } /** * end the animation thread */ private class EndThread implements ActionListener { /** * if there currently is an animation thread, * request that it end * * @param event click of the End button */ public void actionPerformed(ActionEvent event) { // if an animation thread is running, request // that it end and make the animation thread // data field point to nothing if (paintThread != null) { paintThread.interrupt(); paintThread = null; } } } }