import java.awt.Frame; import java.awt.Color; import java.awt.Graphics; import java.awt.Image; // Used to create an image buffer import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.Graphics2D; // Used for anti-aliasing import java.awt.RenderingHints; // Used for anti-aliasing public class GraphicsMoveObjectsWithThreadAndFrame extends Frame implements Runnable { Image image; Graphics graphics; int width = 400, height = 250; int dotSize = 25, dotBlueX = 150, dotBlueY = 70, dotMagentaX = 230, dotMagentaY = 190; int directionBlue = 1, speedBlue = 2, directionMagenta = 1, speedMagenta = 4; public static void main(String[] args) { // Create a thread containing an instance of the // 'GraphicsMoveObjectsWithThreadAndFrame' class // and set the frame background color GraphicsMoveObjectsWithThreadAndFrame frame = new GraphicsMoveObjectsWithThreadAndFrame(); frame.setBackground(Color.WHITE); new Thread(frame).start(); } // Constructor public GraphicsMoveObjectsWithThreadAndFrame() { this.setSize(width, height); this.setTitle("Object Movement with a Thread on a Frame"); this.setLocationRelativeTo(null); this.setResizable(false); this.setVisible(true); // Close and destroy the window (frame) when a closing event is // detected; without this section of code, it can be difficult // for a user to end the program and make the frame go away; // note that with a JFrame (as opposed to a Frame), closing a // window can be handled with a single line of code addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { e.getWindow().dispose(); System.exit(0); } }); } // Since a timer is not being used, this method should be set to // continuously repeat (loop); a thread is used (below) to pause // the loop, which effectively simulates a timer with an interval public void run() { while (true) { // Update the position/direction of the blue dot dotBlueX += speedBlue * directionBlue; if (dotBlueX < 16 || dotBlueX > width - 18) directionBlue = -directionBlue; // Update the position/direction of the magenta dot dotMagentaX += speedMagenta * directionMagenta; if (dotMagentaX < 16 || dotMagentaX > width - 18) directionMagenta = -directionMagenta; repaint(); try { // Pause for 15/1000 seconds (so that the dots do not move // across the frame too quickly Thread.sleep(15); } catch (InterruptedException e) { // This section is required when using 'Thread.sleep()' } } } public void paint(Graphics g) { // Prepare to create the image on a separate 'Image' instance; this // should prevent flickering by using a "buffer" on which the frame // image will first be drawn before it is displayed to the user image = createImage(width, height); graphics = image.getGraphics(); // This line causes graphics and text to be rendered with anti-aliasing // turned on, making the overall display look smoother and cleaner ((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Draw/Redraw the blue dot graphics.setColor(Color.BLUE); graphics.fillOval(dotBlueX - dotSize / 2, dotBlueY - dotSize / 2, dotSize, dotSize); // Draw/Redraw the magenta dot graphics.setColor(Color.MAGENTA); graphics.fillOval(dotMagentaX - dotSize / 2, dotMagentaY - dotSize / 2, dotSize, dotSize); // Display (Draw) the buffered image on the frame g.drawImage(image, 0, 0, null); } }