Reputation: 41
I try to implement two classes, one dedicated to the interface and the other one dedicated to the canvas allowing user to draw shapes on it.
So basically, let's take one of my button, here is my Jbutton bCircle where I want to initialize the action in an anonymous class. I have put just the specific piece :
public class Application extends JFrame implements ActionListener {
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
//Action ?????
}
});
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
}
And in the other class, here is the action I want the selected state of the Jbutton bCircle to execute when I click on the canvas :
public class DrawingCanvas extends JPanel implements MouseListener, MouseMotionListener {
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getSource() == bCircle) {
shapes.add(new Circle(e.getX(),e.getY()));
}
repaint();
}
}
shapes
is a ArrayList stocking the shapes to make the canvas easier to clean, Circle
is a class which only contains drawing of the circle.
At the end, the purpose is to allow user to click first on four buttons representing four shapes, then draw them by a mouse pressed on the canvas. But I don't know how to link theses two classes, please help me,
Thanks in advance,
P.S : the full Application class (interface) that I have updated a second time:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
public class Application extends JFrame implements ActionListener {
{
//Set appearance Look & Feel for the window
try { javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch(Exception e) {
e.printStackTrace();
}
}
private DrawingCanvas canvas = new DrawingCanvas();
private JPanel container = new JPanel();
private JPanel commandes = new JPanel();
private JMenuBar menu = new JMenuBar();
private JMenu newFile = new JMenu();
private JMenu open = new JMenu();
private JMenu save = new JMenu();
private JFileChooser fileChooser;
private JToolBar toolBar = new JToolBar();
private JButton bSquare = new JButton("Square");
private JButton bRectangle = new JButton("Rectangle");
private JButton bCircle = new JButton("Circle");
private JButton bTriangle = new JButton("Triangle");
private JButton bErase = new JButton("CLEAR");
//public static boolean bIsSelected = false;
public Application(){
this.setTitle("Animation");
this.setSize(579, 432);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
container.add(canvas, BorderLayout.CENTER);
this.setContentPane(container);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new SampleActionListener(canvas, new Circle()));
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
bErase.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent erase){
canvas.getShapes().clear();
repaint();
}
});
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
menu.add(newFile);
newFile.setIcon(new ImageIcon("src/images/new.png"));
menu.add(open);
open.setIcon(new ImageIcon("src/images/open.png"));
menu.add(save);
save.setIcon(new ImageIcon("src/images/save.png"));
this.setJMenuBar(menu);
}
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas2;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas2 = canvas;
this.shapeGenerator = shapeGenerator;
}
public void actionPerformed(ActionEvent event) {
this.canvas2.setShapeGenerator(shapeGenerator);
}
}
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Application App = new Application();
}
}
Here is the class for the canvas, uploaded a second time as well :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.JPanel;
public class DrawingCanvas extends JPanel implements MouseListener {
private ArrayList<Shape> shapes = new ArrayList<>();
private Shape shapeUnderMouse = null;
public ArrayList<Shape> getShapes() {
return shapes;
}
public void setShapes(ArrayList<Shape> shapes) {
this.shapes = shapes;
}
public DrawingCanvas() {
super();
addMouseListener(this);
}
public void paint(Graphics g){
for(int i = 0;i < shapes.size();i++){
shapes.get(i).paint(g);
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void addShape(Shape anyShape)
{
shapes.add(anyShape);
}
@Override
public void mousePressed(MouseEvent e) {
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
repaint();
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
// TODO Auto-generated method stub
}
Now, the class shape :
import javax.swing.JPanel;
public class Shape extends JPanel{
protected int posX;
protected int posY;
/*public Shape(int posX, int posY) {
super();
this.posX = posX;
this.posY = posY;
}*/
public int getPosX() {
return posX;
}
public void setPosX(int posX) {
this.posX = posX;
}
public int getPosY() {
return posY;
}
public void setPosY(int posY) {
this.posY = posY;
}
}
My little circle class :
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Float;
import javax.swing.JPanel;
public class Circle extends Shape implements ShapeGenerator{
/*public Circle(int posX, int posY) {
super(posX, posY);
// TODO Auto-generated constructor stub
}*/
public void paint(Graphics g){
g.fillOval(posX,posY,40,40);
g.setColor(Color.blue);
}
public Shape getGeneratedShape(int x, int y) {
return new Ellipse2D.Float(x, y, 10, 10); //--> does not work, ask me to change method type to a float
return new Circle();
}
}
And finally the interface, all the class are in separate classes :
public interface ShapeGenerator {
Shape getGeneratedShape(int posX, int posY);
}
Upvotes: 4
Views: 1065
Reputation: 149
Here is the solution to your problem. But it's really dirty... Like i said, there is no sense to have a Shape that is inhereted from JPanel !!
public class Application extends JFrame implements ActionListener {
{
// Set appearance Look & Feel for the window
try {
javax.swing.UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (Exception e) {
e.printStackTrace();
}
}
private final DrawingCanvas pan = new DrawingCanvas();
// don't use to many field, it's confusing and not necessary.
// you can do local var instead.
private final JPanel container = new JPanel();
private final JPanel commandes = new JPanel();
private final JMenuBar menu = new JMenuBar();
private final JMenu newFile = new JMenu();
private final JMenu open = new JMenu();
private final JMenu save = new JMenu();
private JFileChooser fileChooser;
private final JToolBar toolBar = new JToolBar();
private final JButton bSquare = new JButton("Square");
private final JButton bRectangle = new JButton("Rectangle");
private final JButton bCircle = new JButton("Circle");
private final JButton bTriangle = new JButton("Triangle");
private final JButton bErase = new JButton("CLEAR");
public Application() {
this.setTitle("Animation");
this.setSize(579, 432);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
container.setBackground(Color.white);
container.setLayout(new BorderLayout());
container.add(pan, BorderLayout.CENTER);
this.setContentPane(container);
toolBar.add(Box.createHorizontalGlue());
toolBar.add(Box.createVerticalGlue());
toolBar.add(bSquare, toolBar.getComponentCount() - 1);
toolBar.add(bCircle, toolBar.getComponentCount() - 1);
bCircle.addActionListener(new SampleActionListener(pan, new CircleShapeGenerator()));
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
// bRectangle.addActionListener(new SampleActionListener(pan, new
// RectangleShapeGenerator()));
toolBar.add(bTriangle, toolBar.getComponentCount() - 1);
toolBar.add(bErase, toolBar.getComponentCount() - 1);
toolBar.setOrientation(SwingConstants.VERTICAL);
container.add(toolBar, BorderLayout.WEST);
menu.add(newFile);
newFile.setIcon(new ImageIcon("src/images/new.png"));
menu.add(open);
open.setIcon(new ImageIcon("src/images/open.png"));
menu.add(save);
save.setIcon(new ImageIcon("src/images/save.png"));
this.setJMenuBar(menu);
}
@Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Application App = new Application();
}
}
We keep the CircleShapeGenerator class
public class CircleShapeGenerator implements ShapeGenerator {
@Override
public CircleShape getGeneratedShape(int x, int y) {
CircleShape c = new CircleShape();
c.setCanvasX(x);
c.setCanvasY(y);
return c;
}
}
The circle shape
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
public class CircleShape extends Shape {
private final Ellipse2D.Float ellipse2D;
public CircleShape() {
this.ellipse2D = new Ellipse2D.Float();
this.setRadius(20);
}
private void setRadius(int r) {
this.ellipse2D.height = r;
this.ellipse2D.width = r;
}
@Override
public void setCanvasX(int canvasX) {
this.canvasX = canvasX;
this.ellipse2D.x = canvasX;
}
@Override
public void setCanvasY(int canvasY) {
this.canvasY = canvasY;
this.ellipse2D.y = canvasY;
}
@Override
public java.awt.Shape getTrueShape() {
return this.ellipse2D;
}
}
A class for the contextual menu to edit your shape
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
class ContextualShapeMenu extends JPopupMenu {
private final Shape shape;
public ContextualShapeMenu(Shape shape) {
this.shape = shape;
JMenuItem anItem = new JMenuItem("Edit the size");
add(anItem);
}
}
The DrawingCanvas class
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import com.google.common.collect.Lists;
public class DrawingCanvas extends JPanel implements MouseListener {
protected ArrayList<Shape> shapes = new ArrayList<Shape>();
private ShapeGenerator shapeGenerator;
public ArrayList<Shape> getShapes() {
return shapes;
}
public void setShapes(ArrayList<Shape> shapes) {
this.shapes = shapes;
}
public DrawingCanvas() {
super();
addMouseListener(this);
}
@Override
public void paint(Graphics g) {
super.paint(g);
for (Shape s : shapes) {
s.paint(g);
}
}
@Override
public void mouseClicked(MouseEvent e) {
switch (e.getButton()) {
case MouseEvent.BUTTON1:
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
break;
default:
Shape shape = getShapeUnderMouse(e);
if (shape != null) {
ContextualShapeMenu menu = new ContextualShapeMenu(shape);
menu.show(e.getComponent(), e.getX(), e.getY());
}
}
repaint();
}
private Shape getShapeUnderMouse(MouseEvent e) {
List<Shape> reversed = Lists.reverse(this.shapes);
for (Shape s : reversed) {
if (s.contains(e.getX(), e.getY())) {
return s;
}
}
return null;
}
@Override
public void mouseEntered(MouseEvent e) {
// Do nothing
}
@Override
public void mouseExited(MouseEvent e) {
// Do nothing
}
@Override
public void mousePressed(MouseEvent e) {
// Do nothing
}
@Override
public void mouseReleased(MouseEvent e) {
// Do nothing
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
this.shapeGenerator = shapeGenerator;
}
}
Still the ActionListener. Rename it.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas = canvas;
this.shapeGenerator = shapeGenerator;
}
@Override
public void actionPerformed(ActionEvent event) {
this.canvas.setShapeGenerator(shapeGenerator);
}
}
The ShapeGenerator interface
public interface ShapeGenerator {
Shape getGeneratedShape(int x, int y);
}
And at least, the most stupid class : Shape
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public abstract class Shape extends JPanel implements java.awt.Shape {
protected int canvasX;
protected int canvasY;
public int getCanvasX() {
return canvasX;
}
public abstract java.awt.Shape getTrueShape();
public abstract void setCanvasX(int canvasX);
public int getCanvasY() {
return canvasY;
}
public abstract void setCanvasY(int canvasY);
@Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(this.getTrueShape());
}
@Override
public Rectangle getBounds() {
return getTrueShape().getBounds();
}
@Override
public Rectangle2D getBounds2D() {
return getTrueShape().getBounds2D();
}
@Override
public boolean contains(int x, int y) {
return this.getTrueShape().contains(x, y);
}
@Override
public boolean contains(double x, double y) {
return this.getTrueShape().contains(x, y);
}
@Override
public boolean contains(Point2D p) {
return this.getTrueShape().contains(p);
}
@Override
public boolean contains(Point p) {
return this.getTrueShape().contains(p);
}
@Override
public boolean intersects(double x, double y, double w, double h) {
return this.getTrueShape().intersects(x, y, w, h);
}
@Override
public boolean intersects(Rectangle2D r) {
return this.getTrueShape().intersects(r);
}
@Override
public boolean contains(double x, double y, double w, double h) {
return this.getTrueShape().contains(x, y, w, h);
}
@Override
public boolean contains(Rectangle2D r) {
return this.getTrueShape().contains(r);
}
@Override
public PathIterator getPathIterator(AffineTransform at) {
return this.getTrueShape().getPathIterator(at);
}
@Override
public PathIterator getPathIterator(AffineTransform at, double flatness) {
return this.getTrueShape().getPathIterator(at, flatness);
}
}
I have add the guava librairy, so, you will not find the Lists class. Add it to your project, use a other librairy or create a method to reverse your list.
Good luck and don't make something like that in the future !!! It's coding horror.
By the way, i came from France.
Upvotes: 0
Reputation: 149
First of all, remove your class Shape. You don't need to. Shape is a interface defined by Java. Use this interface instead.
Your setter for ShapeGenerator in the DrawingCanvas class do nothing. So add it. Your method paint is not correct.
public class DrawingCanvas extends JPanel implements MouseListener {
// Shape here is the java.awt.Shape from java.
private ArrayList<Shape> shapes = new ArrayList<>();
private ShapeGenerator shapeGenerator;
...
...
public void paint(Graphics g){
super.paint(g);
for (Shape s : shapes) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(s);
}
}
...
@Override
public void mousePressed(MouseEvent e) {
shapes.add(this.shapeGenerator.getGeneratedShape(e.getX(), e.getY()));
repaint();
}
public void setShapeGenerator(ShapeGenerator shapeGenerator) {
this.shapeGenerator = shapeGenerator;
}
}
You class Circle is really to complex. It's simple and this method don't need any paint method. You class Circle is really simple :
public class Circle implements ShapeGenerator{
public Shape getGeneratedShape(int x, int y) {
// This will return a java.awt.Shape instance
return new Ellipse2D.Float(x, y, 10, 10);
}
}
And i thinks, that's all.
Upvotes: 0
Reputation: 149
In fact, it's pretty easy. Don't use anonymous class.
For example, with your code, you just have to attach a defined listener. For example :
bCircle.addActionListener(new SampleActionListener(pan, new CircleShapeGenerator()));
Here is the SampleActionListener witch implements the ActionListener interface
public class SampleActionListener implements ActionListener {
private final DrawingCanvas canvas;
private final ShapeGenerator shapeGenerator;
public SampleActionListener(DrawingCanvas canvas, ShapeGenerator shapeGenerator) {
this.canvas = canvas;
this.shapeGenerator = shapeGenerator;
}
public void actionPerformed(ActionEvent event) {
this.canvas.setShapeGenerator(shapeGenerator);
}
}
Here is the class CircleShapeGenerator
public class CircleShapeGenerator implements ShapeGenerator {
public Shape getGeneratedShape(int x, int y) {
return new Ellipse2D.Float(x, y, 10, 10);
}
}
and the interface ShapeGenerator
public interface ShapeGenerator {
Shape getGeneratedShape(int x, int y);
}
and, if you want to add the action listener on the rectangle button, it's really easy now. create this class:
public class RectangleShapeGenerator implements ShapeGenerator {
public Shape getGeneratedShape(int x, int y) {
return new Rectangle2D.Float(x, y, 10, 10);
}
}
and in your application class, add the following code
toolBar.add(bRectangle, toolBar.getComponentCount() - 1);
bRectangle.addActionListerner(pan, new RectangleShapeGenerator() )
for your method paint in your DrawingCanvas, i think, you should use a code like this :
for (Shape s : shapes) {
Graphics2D g2 = (Graphics2D) g;
g2.draw(s);
}
BR, Patouche
Sorry for my english, i know it's not really perfect...
Upvotes: 2