My java assignment is to create a program that lets the user create a christmas card. The following code shows that. I have currently run into some difficulty though with implementation of some of the buttons. Although I have many questions, I just started working on this tonight and won't ask them all. Currently I am stuck on the resize portion of the project. I have asked the user for the number they want to resize to and it reads it in, but I do not know how to select the figure and the object that corresponds to it in order to use the resize function. I'll include my main, MyShape, MyText, and a figure so you understand how it works. Thanks for any help!
The majority of the code I changed/wrote was from the beginning up to the MyShape class. The teacher gave us a base to write our program off of. I have the other buttons added on except for the snowman and have most of the other buttons created. a few work completely, but I just started tonight. Thanks again.
// CS 401 Fall 2011
// For additional help, see Sections 14.5-14.6 in the text
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.awt.print.*;
// Create enum types that will be useful in the program
enum Figures {TREE,SNOWFLAKE,GREETING,HOUSE,GIFT};
enum Mode {NONE,DRAW,SELECTED,MOVING,RESIZE};
// Code extracted from Oracle Java Example programs. See link below for full code:
// http://docs.oracle.com/javase/tutori...tUIWindow.java
class thePrintPanel implements Printable
{
JPanel panelToPrint;
public int print(Graphics g, PageFormat pf, int page) throws
PrinterException
{
if (page > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
/* User (0,0) is typically outside the imageable area, so we must
* translate by the X and Y values in the PageFormat to avoid clipping
*/
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
/* Now print the window and its visible contents */
panelToPrint.printAll(g);
/* tell the caller that this page is part of the printed document */
return PAGE_EXISTS;
}
public thePrintPanel(JPanel p)
{
panelToPrint = p;
}
}
public class Assig5
{
private ShapePanel drawPanel;
private JPanel buttonPanel;
private JButton makeShape;
private JRadioButton makeTree, makeFlake, makeGreet, makeHouse, makeGift;
private ButtonGroup shapeGroup;
private Figures currShape;
private JLabel msg;
private JMenuBar theBar, editBar;
private JMenu fileMenu, editMenu;
private JMenuItem newScene, openScene, saveScene,saveAsScene, endProgram, printScene,cutItem,copyItem,pasteItem;
private JPopupMenu popper;
private JMenuItem delete,resize;
private JFrame theWindow;
private StringBuilder Shapes;
// This ArrayList is used to store the shapes in the program.
// It is specified to be of type MyShape, so objects of any class
// that implements the MyShape interface can be stored in here.
// See Section 8.13 in your text for more info on ArrayList.
private ArrayList<MyShape> shapeList;
private ArrayList<MyShape> saveList;
private MyShape newShape;
public Assig5()
{
drawPanel = new ShapePanel(500, 300);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(3, 2));
makeShape = new JButton("Make Shape");
ButtonHandler bhandler = new ButtonHandler();
makeShape.addActionListener(bhandler);
buttonPanel.add(makeShape);
msg = new JLabel("");
buttonPanel.add(msg);
makeTree = new JRadioButton("Tree", false);
makeFlake = new JRadioButton("Snowflake", true);
makeGreet = new JRadioButton("Greeting", false);
makeHouse = new JRadioButton("House",false);
makeGift = new JRadioButton("Gift",false);
RadioHandler rhandler = new RadioHandler();
makeTree.addItemListener(rhandler);
makeFlake.addItemListener(rhandler);
makeGreet.addItemListener(rhandler);
makeHouse.addItemListener(rhandler);
makeGift.addItemListener(rhandler);
buttonPanel.add(makeFlake);
buttonPanel.add(makeTree);
buttonPanel.add(makeGreet);
buttonPanel.add(makeHouse);
buttonPanel.add(makeGift);
// A ButtonGroup allows a set of JRadioButtons to be associated
// together such that only one can be selected at a time
shapeGroup = new ButtonGroup();
shapeGroup.add(makeFlake);
shapeGroup.add(makeTree);
shapeGroup.add(makeGreet);
shapeGroup.add(makeHouse);
shapeGroup.add(makeGift);
currShape = Figures.SNOWFLAKE;
drawPanel.setMode(Mode.NONE);
theWindow = new JFrame("CS 401 Assig5 Greeting Card!");
Container c = theWindow.getContentPane();
drawPanel.setBackground(Color.lightGray);
c.add(drawPanel, BorderLayout.NORTH);
c.add(buttonPanel, BorderLayout.SOUTH);
// Note how the menu is created. First we make a JMenuBar, then
// we put a JMenu in it, then we put JMenuItems in the JMenu. We
// can have multiple JMenus if we like. JMenuItems generate
// ActionEvents, just like JButtons, so we just have to link an
// ActionListener to them.
theBar = new JMenuBar();
theWindow.setJMenuBar(theBar);
fileMenu = new JMenu("File");
theBar.add(fileMenu);
newScene = new JMenuItem("New");
openScene = new JMenuItem("Open");
saveScene = new JMenuItem("Save");
saveAsScene = new JMenuItem("Save As");
printScene = new JMenuItem("Print");
endProgram = new JMenuItem("Exit");
fileMenu.add(newScene);
fileMenu.add(openScene);
fileMenu.add(saveScene);
fileMenu.add(saveAsScene);
fileMenu.add(printScene);
fileMenu.add(endProgram);
newScene.addActionListener(bhandler);
openScene.addActionListener(bhandler);
saveScene.addActionListener(bhandler);
saveAsScene.addActionListener(bhandler);
printScene.addActionListener(bhandler);
endProgram.addActionListener(bhandler);
editMenu = new JMenu("Edit");
theBar.add(editMenu);
cutItem = new JMenuItem("Cut");
copyItem = new JMenuItem("Copy");
pasteItem = new JMenuItem("Paste");
editMenu.add(cutItem);
editMenu.add(copyItem);
editMenu.add(pasteItem);
// JPopupMenu() also holds JMenuItems. To see how it is actually
// brought out, see the mouseReleased() method in the ShapePanel class
// below.
popper = new JPopupMenu();
delete = new JMenuItem("Delete");
resize = new JMenuItem("Resize");
delete.addActionListener(bhandler);
resize.addActionListener(bhandler);
popper.add(delete);
popper.add(resize);
theWindow.setDefaultCloseOperation(WindowConstants .DO_NOTHING_ON_CLOSE);
theWindow.pack();
theWindow.setVisible(true);
}
public static void main(String [] args)
{
new Assig5();
}
// See Section 7.5 for information on JRadioButtons. Note that the
// text uses ActionListeners to handle JRadioButtons. Clicking on
// a JRadioButton actually generates both an ActionEvent and an
// ItemEvent. I am using the ItemEvent here. To handle the event,
// all I am doing is changing a state variable that will affect the
// MouseListener in the ShapePanel.
private class RadioHandler implements ItemListener
{
public void itemStateChanged(ItemEvent e)
{
if (e.getSource() == makeTree)
currShape = Figures.TREE;
else if (e.getSource() == makeFlake)
currShape = Figures.SNOWFLAKE;
else if (e.getSource() == makeGreet)
currShape = Figures.GREETING;
else if(e.getSource() == makeHouse)
currShape = Figures.HOUSE;
else if(e.getSource()== makeGift)
currShape = Figures.GIFT;
}
}
// Note how the makeShape button and moveIt menu item are handled
// -- we again simply set the state in the panel so that the mouse will
// actually do the work. The state needs to be set back in the mouse
// listener.
private class ButtonHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == makeShape)
{
drawPanel.setMode(Mode.DRAW);
msg.setText("Position new shape with mouse");
makeShape.setEnabled(false);
}
else if (e.getSource() == delete)
{
boolean ans = drawPanel.deleteSelected();
if (ans)
{
msg.setText("Shape deleted");
drawPanel.repaint();
}
}
else if(e.getSource() == resize)
{
String resizeOption = JOptionPane.showInputDialog("Enter the new size: ");
int resizeNum = Integer.parseInt(resizeOption);
//how to get the shape then reisze?
}
else if (e.getSource() == printScene)
{
Printable thePPanel = new thePrintPanel(drawPanel);
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(thePPanel);
boolean ok = job.printDialog();
if (ok)
{
try {
job.print();
}
catch (PrinterException ex) {
/* The job did not successfully complete */
}
}
}
else if (e.getSource() == endProgram)
{
System.exit(0);
}
else if (e.getSource() == saveScene)
{
//It chosesfile correctly, just doensn't output what i want
String fname;
fname = JOptionPane.showInputDialog("Enter file name: ");
ArrayList copyOfShapeList = new ArrayList();
copyOfShapeList.addAll(shapeList);
Shapes = new StringBuilder();
StringBuilder S1= new StringBuilder();
//S1 = shapeList.clone();
//saveList = shapeList.clone();
int arraysize = copyOfShapeList.size();
Shapes.append(arraysize);
for(int i=0; i<=(arraysize-1);i++)
{
Shapes.append(copyOfShapeList.indexOf(i));
}
try
{
PrintWriter out = new PrintWriter(new FileWriter(fname));
out.print(Shapes);
out.close();
}catch(IOException w){
}
}
else if (e.getSource() == saveAsScene)
{
//Code for save as
}
else if (e.getSource() == newScene)
{
//Code for new Scene
shapeList.clear();
drawPanel.removeAll();
drawPanel.updateUI();
}
}
}
// Here we are extending JPanel. This way we can use all of the
// properties of JPanel (including generating MouseEvents) and also
// add new instance data and methods, as shown below. Since this is
// an inner class, it can access instance variables from the A5Help
// class if necessary.
private class ShapePanel extends JPanel
{
// These instance variables are used to store the desired size
// of the panel
private int prefwid, prefht;
// Store index of the selected MyShape. This allows the Shape
// to be moved and updated.
private int selindex;
// Keep track of positions where mouse is moved on the display.
// This is used by mouse event handlers when moving the shapes.
private int x1, y1, x2, y2;
private boolean popped; // has popup menu been activated?
private Mode mode; // Keep track of the current Mode
public ShapePanel (int pwid, int pht)
{
shapeList = new ArrayList<MyShape>();
//saveList = new ArrayList<String>();// create empty ArrayList
selindex = -1;
prefwid = pwid; // values used by getPreferredSize method below
prefht = pht; // (which is called implicitly). This enables
// the JPanel to request the room that it needs.
// However, the JFrame is not required to honor
// that request.
setOpaque(true);// Paint all pixels here (See API)
setBackground(Color.lightGray);
addMouseListener(new MyMouseListener());
addMouseMotionListener(new MyMover());
popped = false;
} // end of constructor
// This class is extending MouseAdapter. MouseAdapter is a predefined
// class that implements MouseListener in a trivial way (i.e. none of
// the methods actually do anything). Extending MouseAdapter allows
// a programmer to implement only the MouseListener methods that
// he/she needs but still satisfy the interface (recall that to
// implement an interface one must implement ALL of the methods in the
// interface -- in this case I do not need 3 of the 5 MouseListener
// methods)
private class MyMouseListener extends MouseAdapter
{
public void mousePressed(MouseEvent e)
{
x1 = e.getX(); // store where mouse is when clicked
y1 = e.getY();
if (!e.isPopupTrigger() && (mode == Mode.NONE ||
mode == Mode.SELECTED)) // left click and
{ // either NONE or
if (selindex >= 0) // SELECTED mode
{
unSelect(); // unselect previous shape
mode = Mode.NONE;
}
selindex = getSelected(x1, y1); // find shape mouse is
// clicked on
if (selindex >= 0)
{
mode = Mode.SELECTED; // Now in SELECTED mode for shape
// Check for double-click. If so, show dialog to update text of
// the current text shape (will do nothing if shape is not a MyText)
MyShape curr = shapeList.get(selindex);
if (curr instanceof MyText && e.getClickCount() == 2)
{
String newText = JOptionPane.showInputDialog(theWindow, "Enter new text [Cancel for no change]");
if (newText != null)
((MyText) curr).setText(newText);
}
}
repaint();
}
else if (e.isPopupTrigger() && selindex >= 0) // if button is
{ // the popup menu
popper.show(ShapePanel.this, x1, y1); // trigger, show
popped = true; // popup menu
}
}
public void mouseReleased(MouseEvent e)
{
if (mode == Mode.DRAW) // in DRAW mode, create the new Shape
{ // and add it to the list of Shapes
if (currShape == Figures.TREE)
{
newShape = new Tree(x1,y1,50);
}
else if (currShape == Figures.SNOWFLAKE)
{
newShape = new Snowflake(x1,y1,10);
}
else if (currShape == Figures.GREETING)
{
newShape = new Greeting(x1,y1,30);
}
else if(currShape == Figures.HOUSE)
{
newShape = new House(x1,y1,50);
}
else if(currShape == Figures.GIFT)
{
newShape = new Gift(x1,y1,30);
}
addShape(newShape);
makeShape.setEnabled(true); // Set interface back to
mode = Mode.NONE; // "base" state
msg.setText("");
}
// In MOVING mode, set mode back to NONE and unselect shape (since
// the move is now finished).
else if (mode == Mode.MOVING)
{
mode = Mode.NONE;
unSelect();
makeShape.setEnabled(true);
msg.setText("");
repaint();
}
else if (e.isPopupTrigger() && selindex >= 0) // if button is
{ // the popup menu trigger, show the
popper.show(ShapePanel.this, x1, y1); // popup menu
}
popped = false; // unset popped since mouse is being released
}
}
// the MouseMotionAdapter has the same idea as the MouseAdapter
// above, but with only 2 methods. The method not implemented
// here is mouseMoved
private class MyMover extends MouseMotionAdapter
{
public void mouseDragged(MouseEvent e)
{
x2 = e.getX(); // store where mouse is now
y2 = e.getY();
// Note how easy moving the shapes is, since the "work"
// is done within the various shape classes. All we do
// here is call the appropriate method. However, we don't
// want to accidentally move the selected shape with a right click
// so we make sure the popup menu has not been activated.
if ((mode == Mode.SELECTED || mode == Mode.MOVING) && !popped)
{
MyShape s = shapeList.get(selindex);
mode = Mode.MOVING;
s.move(x2, y2);
}
repaint(); // Repaint screen to show updates
}
}
// Check to see if point (x,y) is within any of the shapes. If
// so, select that shape and highlight it so user can see.
// This version of getSelected() always considers the shapes from
// beginning to end of the ArrayList. Thus, if a shape is "under"
// or "within" a shape that was previously created, it will not
// be possible to select the "inner" shape. In your assignment you
// must redo this method so that it allows all shapes to be selected.
// Think about how you would do this.
private int getSelected(double x, double y)
{
for (int i = 0; i < shapeList.size(); i++)
{
if (shapeList.get(i).contains(x, y))
{
shapeList.get(i).highlight(true);
return i;
}
}
return -1;
}
public void unSelect()
{
if (selindex >= 0)
{
shapeList.get(selindex).highlight(false);
selindex = -1;
}
}
public boolean deleteSelected()
{
if (selindex >= 0)
{
shapeList.remove(selindex);
selindex = -1;
return true;
}
else return false;
}
public void setMode(Mode newMode) // set Mode
{
mode = newMode;
}
private void addShape(MyShape newshape) // Add shape
{
shapeList.add(newshape);
repaint(); // repaint so we can see new shape
}
// Method called implicitly by the JFrame to determine how much
// space this JPanel wants
public Dimension getPreferredSize()
{
return new Dimension(prefwid, prefht);
}
// This method enables the shapes to be seen. Note the parameter,
// which is implicitly passed. To draw the shapes, we in turn
// call the draw() method for each shape. The real work is in the draw()
// method for each MyShape
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++)
{
shapeList.get(i).draw(g2d);
}
}
} // end of ShapePanel
}
// CS 401 Fall 2011
// MyShape interface for Assignment 5
// See the method descriptions below and see the example implementation
// in classes Snowflake and Tree. For the assignment you must complete
// the additional implementations in classes Snowman and House.
import java.awt.*;
public interface MyShape
{
// Draw the shape onto the Graphics2D context g.
public void draw(Graphics2D g);
// Move the shape's position from its previous location to location
// (x,y). Note that (x,y) is simply a reference point for the
// shape (ex: the lower right corner).
public void move(int x, int y);
// Set the shape to be highlighted or not. This method can be used
// to indicate that the shape has been selected. There are different
// ways to hightlight a object. Two examples are:
// 1) Change its color when it is drawn
// 2) Draw the perimeter of the underlying Shapes rather than filling
// them in. For more information on this, see the Shape interface
// and the draw() and fill() methods.
public void highlight(boolean b);
// Check to see if the point (x,y) is within the shape. This can
// be implemented by testing to see if (x,y) is within the underlying
// components of the shape.
public boolean contains(double x, double y);
// Resize the object to newsize. Keep it in the same location.
public void resize(int newsize);
// Return a String representing this object. The string should
// have the following format:
// ClassName:X:Y:size
public String saveData();
}
// CS 401 Fall 2011
// Tree class as another implementation of the MyShape interface.
// This class also uses composition, with 2 Polygons being the primary
// components of a Tree object. For more information on Polygons, see
// the Java API.
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
class Tree implements MyShape
{
// Represent a Tree in two parts -- a Polygon for the top part
// (the branches) and another Polygon for the trunk. Since the
// trunk is rectangular, a Rectangle2D could have been used, but
// to keep consistent (especially with the move() method) I used
// Polygon objects for both.
private Polygon canopy;
private Polygon trunk;
// X, Y and size instance variables
private int X, Y;
private int size;
private boolean isHighlighted;
// Create a new Tree object. Note how the Polygons are built,
// adding one point at a time to each. If you plot the points out
// on paper you will see how the shapes are formed.
public Tree(int startX, int startY, int sz)
{
X = startX;
Y = startY;
size = sz;
canopy = new Polygon();
canopy.addPoint(X,Y);
canopy.addPoint(X-size,Y);
canopy.addPoint(X-size/2,Y-5*size/3);
trunk = new Polygon();
trunk.addPoint(X-3*size/8,Y);
trunk.addPoint(X-5*size/8,Y);
trunk.addPoint(X-5*size/8,Y+size/2);
trunk.addPoint(X-3*size/8,Y+size/2);
}
public void highlight(boolean b)
{
isHighlighted = b;
}
// The Polygon class can also be drawn with a predefined method in
// the Graphics2D class. There are two versions of this method:
// 1) draw() which only draws the outline of the shape
// 2) fill() which draws a solid shape
// In this class the draw() method is used when the object is
// highlighted.
public void draw(Graphics2D g)
{
g.setColor(Color.green);
if (isHighlighted)
g.draw(canopy);
else
g.fill(canopy);
g.setColor(Color.orange);
if (isHighlighted)
g.draw(trunk);
else
g.fill(trunk);
}
// Looking at the API, we see that Polygon has a translate() method
// which can be useful to us. All we have to do is calculate the
// difference of the new (x,y) and the old (X,Y) and then call
// translate() for both parts of the tree.
public void move(int x, int y)
{
int deltaX = x - X;
int deltaY = y - Y;
canopy.translate(deltaX, deltaY);
trunk.translate(deltaX, deltaY);
X = x;
Y = y;
}
// Polygon also has a contains() method, so this method is also
// simple
public boolean contains(double x, double y)
{
if (canopy.contains(x,y))
return true;
if (trunk.contains(x,y))
return true;
return false;
}
// The move() method for the Polygons that are in Tree are not
// reconfigured like in Snowflake, so we can't use the trick used
// there. Instead, we just create new Polygons with the new size.
// The old ones will be garbage collected by the system.
public void resize(int newsize)
{
size = newsize;
canopy = new Polygon();
canopy.addPoint(X,Y);
canopy.addPoint(X-size,Y);
canopy.addPoint(X-size/2,Y-5*size/3);
trunk = new Polygon();
trunk.addPoint(X-3*size/8,Y);
trunk.addPoint(X-5*size/8,Y);
trunk.addPoint(X-5*size/8,Y+size/2);
trunk.addPoint(X-3*size/8,Y+size/2);
}
// Note again the format
public String saveData()
{
return ("Tree:" + X + ":" + Y + ":" + size);
}
}
// CS 401 Fall 2011
// MyText interface for Assignment 5
// This interface simply adds one method to MyShape (note that it inherits
// the other methods, so a class implementing MyText must also implement
// all of the MyShape methods)
public interface MyText extends MyShape
{
public void setText(String newText);
/* Note: saveData is not a new method for this interface, but the format
requires an additional field for the text. Thus, for MyText objects,
the output to saveData will be
ClassName:X:Y:size:text
public String saveData();
*/
}