import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.util.ArrayList; import java.util.List; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.event.MouseInputAdapter; /** * This class represents a drawing surface that can draw lines between points * where the user clicks the mouse. * This version also responds to various keyboard events to change colors, * scale, rotate, and translate the drawings on the screen. * * @author Marty Stepp * @version CSE 331 Spring 2011, 05/11/2011 */ public class LineCanvas extends JComponent { private static final long serialVersionUID = 1L; private List clicks; // past points the user has clicked private Point mousePosition; // mouse pointer's current position private Color color; private int yOffset; private double scale; private double rotation; /** * Constructs a new empty canvas with no lines. */ public LineCanvas() { clicks = new ArrayList(); mousePosition = null; color = Color.BLACK; yOffset = 0; scale = 1.0; // listen to mouse events LineClickListener listener = new LineClickListener(); addMouseListener(listener); addMouseMotionListener(listener); addKeyListener(new LineKeyListener()); this.setFocusable(true); } /** * Draws all previously touched points and lines on this canvas. */ public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(3)); // apply transformations based on past key presses g2.translate(0, yOffset); g2.scale(scale, scale); g2.rotate(rotation); // draw previously clicked points as circles with lines between g2.setColor(color); Point prev = null; for (Point p : clicks) { Ellipse2D dot = new Ellipse2D.Double(p.getX(), p.getY(), 5, 5); g2.fill(dot); if (prev != null) { // line between previous point and current point Line2D line = new Line2D.Double(prev, p); g2.draw(line); } prev = p; } // draw a hovering red line to the mouse's current position, if // necessary if (mousePosition != null && !clicks.isEmpty()) { Point lastClick = clicks.get(clicks.size() - 1); Line2D line = new Line2D.Double(lastClick, mousePosition); g2.setColor(Color.RED); g2.draw(line); } } // This listener handles mouse events in the canvas. private class LineClickListener extends MouseInputAdapter { /** * Handles mouse clicks by drawing a new line to the point clicked. */ public void mouseClicked(MouseEvent e) { // System.out.println("The mouse was clicked"); // If the user double-clicks, add a point to draw a line if (e.getClickCount() >= 2) { clicks.add(e.getPoint()); repaint(); } } /** * Handles mouse clicks by showing a red hovering line from the previous * click point to the most recent point clicked. */ public void mouseMoved(MouseEvent e) { mousePosition = e.getPoint(); repaint(); } } // This listener handles mouse events in the canvas. private class LineKeyListener extends KeyAdapter { /** * Handles key presses in the canvas by allowing the user to select * colors or apply transformations. */ public void keyPressed(KeyEvent event) { System.out.println("A key was pressed by " + event.getSource()); if (event.getKeyChar() == 'c') { color = JColorChooser.showDialog(null, "Pick a color", Color.BLACK); repaint(); } else if (event.getKeyCode() == KeyEvent.VK_DOWN) { // down arrow; translate down yOffset += 5; repaint(); } else if (event.getKeyChar() == '+') { // + key scales up slightly scale += 0.1; repaint(); } else if (event.getKeyChar() == 'r') { // r key rotates slightly rotation += Math.PI / 100; // radians repaint(); } } } }