// CS 1520 Summer 2011 Example 1b // This has the same functionality as ex1, but is implemented in a slightly // different way. The point is to show how things can be done in several // different ways in Java. I have removed the comments from the original file. The // commments below deal with the differences in this version. import javax.swing.*; import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import java.util.*; enum Mode { NONE, RECT, LINE, ELL }; // We no longer need the "NONE" Mode but // I left it in the type public class ex1b { private ShapePanel drawPanel; private JPanel buttonPanel; private JButton drawRect, drawLine, drawEll; private TextField msg; // Now we have two MouseListeners and two MouseMotionListeners -- one for creating // a shape and one for moving a shape. The program will switch between the two // as necessary. private MakeShapeMotionListener makeMotionListener = new MakeShapeMotionListener(); private MakeShapeListener makeMouseListener = new MakeShapeListener(); private MoveShapeMotionListener moveMotionListener = new MoveShapeMotionListener(); private MoveShapeListener moveMouseListener = new MoveShapeListener(); private JFrame f; // These variables were in ShapePanel in the original version. However, since // they must now be shared by a couple different classes, they have been // moved up to the ex1b class. Also due to access issues some additional // methods had to be created for the ShapePanel class -- see below. private boolean created; private int x1, y1, x2, y2; private int selindex; private Shape newShape; public ex1b() { f = new JFrame("Java Example 1b"); drawPanel = new ShapePanel(400, 190); buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout (2,2)); drawRect = new JButton("Draw Rect"); drawLine = new JButton("Draw Line"); drawEll = new JButton("Draw Ell"); ButtonHandler bhandler = new ButtonHandler(); drawRect.addActionListener(bhandler); drawLine.addActionListener(bhandler); drawEll.addActionListener(bhandler); buttonPanel.add(drawRect); buttonPanel.add(drawLine); buttonPanel.add(drawEll); drawPanel.addMouseListener(moveMouseListener); drawPanel.addMouseMotionListener(moveMotionListener); drawPanel.setMode(Mode.NONE); msg = new TextField(""); msg.setEditable(false); buttonPanel.add(msg); //Container c = getContentPane(); drawPanel.setBackground(Color.white); f.add(drawPanel, BorderLayout.CENTER); f.add(buttonPanel, BorderLayout.SOUTH); f.pack(); //setSize(500,500); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } public static void main(String [] args) { new ex1b(); } private class ButtonHandler implements ActionListener { public void actionPerformed(ActionEvent e) { // Clicking any of the buttons indicates that a new Shape will // be drawn. Switch in the appropriate mouse listeners to // handle this. drawPanel.removeMouseListener(moveMouseListener); drawPanel.removeMouseMotionListener(moveMotionListener); drawPanel.addMouseListener(makeMouseListener); drawPanel.addMouseMotionListener(makeMotionListener); if (e.getSource() == drawRect) { drawPanel.setMode(Mode.RECT); msg.setText("Use Mouse to Draw Rect"); } else if (e.getSource() == drawEll) { drawPanel.setMode(Mode.ELL); msg.setText("Use Mouse to Draw Ellipse"); } else // e.getSource == drawLine { drawPanel.setMode(Mode.LINE); msg.setText("Use Mouse to Draw Line"); } } } // MouseListener for creating a new shape. Note that it is simply // initializing some variables on mousePressed and changing the listeners // back to the "move shape" versions on mouseReleased. private class MakeShapeListener extends MouseAdapter { public void mousePressed(MouseEvent e) { x1 = e.getX(); y1 = e.getY(); created = false; // a new shape is about to // be drawn } public void mouseReleased(MouseEvent e) { drawPanel.removeMouseListener(makeMouseListener); drawPanel.removeMouseMotionListener(makeMotionListener); drawPanel.addMouseListener(moveMouseListener); drawPanel.addMouseMotionListener(moveMotionListener); msg.setText(""); } } // Listener for "moving shapes". We no longer have to test the mode here // since this listener will not be used when a shape is being generated. private class MoveShapeListener extends MouseAdapter { public void mousePressed(MouseEvent e) { x1 = e.getX(); y1 = e.getY(); selindex = drawPanel.getSelected(x1, y1); if (selindex >= 0) msg.setText("Moving Shape"); drawPanel.repaint(); } public void mouseReleased(MouseEvent e) { if (selindex >= 0) { drawPanel.setColor(selindex, Color.black); selindex = -1; // actions end when mouse is drawPanel.repaint(); // released, so set back msg.setText(""); } } } // Listener to generated a new Shape. We still need the "Modes" for the // different object types, but "NONE" is no longer needed since we use a // different listener in that case. private class MakeShapeMotionListener extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { x2 = e.getX(); y2 = e.getY(); Mode mode = drawPanel.getMode(); if (mode == Mode.RECT || mode == Mode.ELL) { if (!created) { if (mode == Mode.RECT) newShape = new Rectangle2D.Double (x1, y1, (x2 - x1), (y2 - y1)); else newShape = new Ellipse2D.Double (x1, y1, (x2 - x1), (y2 - y1)); drawPanel.addshape(newShape); created = true; } else { int startx, starty, delx, dely; if (x2 > x1) { startx = x1; delx = x2-x1; } else { startx = x2; delx = x1-x2; } if (y2 > y1) { starty = y1; dely = y2-y1; } else { starty = y2; dely = y1 - y2; } ((RectangularShape) newShape). setFrame(startx, starty, delx, dely); } } else if (mode == Mode.LINE) // same idea as above { // but for Line2D object if (!created) { newShape = new Line2D.Double(x1, y1, x2, y2); drawPanel.addshape(newShape); created = true; } else ((Line2D) newShape).setLine(x1, y1, x2, y2); } drawPanel.repaint(); } } // Listener for moving an existing object private class MoveShapeMotionListener extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { if (selindex >= 0) { x2 = e.getX(); // store where mouse is now y2 = e.getY(); // Now we need a method to get the shape from the drawPanel // (alternatively, we could move the arraylists up into the ex1b // class). RectangularShape r = (RectangularShape) drawPanel.getShape(selindex); int width = (int) r.getWidth(); int height = (int) r.getHeight(); int oldx = (int) r.getX(); int oldy = (int) r.getY(); int startx = oldx + (x2 - x1); int starty = oldy + (y2 - y1); x1 = x2; y1 = y2; r.setFrame(startx, starty, width, height); drawPanel.repaint(); } } } private class ShapePanel extends JPanel { private ArrayList shapeList; private ArrayList colorList; private int prefwid, prefht; private Mode mode; private int starti = 0; private boolean created; public ShapePanel (int pwid, int pht) { shapeList = new ArrayList(); colorList = new ArrayList(); selindex = -1; prefwid = pwid; prefht = pht; setOpaque(true); } // end of constructor private int getSelected(double x, double y) { for (int i = 0; i < shapeList.size(); i++) { int curr = (i + starti) % shapeList.size(); if (shapeList.get(curr).contains(x, y)) { colorList.set(curr, Color.red); starti = (curr + 1) % shapeList.size(); return curr; } } return -1; } // Some new methods are needed now since the listeners are not within // the ShapePanel class anymore public Shape getShape(int i) { return (shapeList.get(i)); } public void setColor(int i, Color c) { colorList.set(i, c); } public void setMode(Mode newMode) { mode = newMode; } public Mode getMode() { return mode; } private void addshape(Shape newshape) { shapeList.add(newshape); colorList.add(Color.black); repaint(); } public Dimension getPreferredSize() { return new Dimension(prefwid, prefht); } public void paintComponent (Graphics g) { super.paintComponent(g); // don't forget this line! Graphics2D g2d = (Graphics2D) g; for (int i = 0; i < shapeList.size(); i++) { g2d.setColor(colorList.get(i)); g2d.draw(shapeList.get(i)); } } } // end of ShapePanel } // end of ex1b