SeverelyConfused
SeverelyConfused

Reputation: 55

JComboBox change shapes and colors

Right now I have a program that can move a rectangle left and right. I would like to make a JComboBox to change the shape and color of the object.

public class DrawShapes extends JFrame{
//code
    private CanvasDrawArea canvas; // the custom drawing canvas (extends JPanel)
    /** Constructor to set up the GUI */
    public DrawShapes() {
        // Panel for JComboBox and buttons
        JPanel btnPanel = new JPanel(new FlowLayout());
        JComboBox shapes = new JComboBox(shapeName);
        btnPanel.add(shapes);
        //code for left/right buttons
    }
}

So above is the class that contains everything and the constructor that sets up the GUI. I also have an inner class that creates the shape

class CanvasDrawArea extends JPanel {
    public void paintComponent(Graphics rect) {
        super.paintComponent(rect);
        setBackground(CANVAS_BACKGROUND);
        rect.setColor(Color.BLUE);
        rect.fillRect(x1, y1, rectWidth, rectHeight); //these int are defined earlier
    }
}

I thought if I wanted to change the shape with the JComboBox, I would need to place the ActionListener for the JComboBox in the CanvasDrawArea class (the inner class). But if I do that, I can't add the shape JComboBox in the btnPanel. So how would I change the shape and color of the object being moved?

Here is the full code as of writing this question in case someone wants to look at it.

Edit: This is my current JPanel for my buttons. I only copied the code for the combo box.

JPanel btnPanel = new JPanel(new FlowLayout());
JComboBox shapes = new JComboBox(shapeName);
shapes.setSelectedIndex(1);
btnPanel.add(shapes);
shapes.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent e) {
        JComboBox cb = (JComboBox)e.getSource(); //copies shapes combo box
        String msg = (String)cb.getSelectedItem();
        switch(msg){
            case "Rectangle":
                Rectangle blueRect = new Rectangle(x1, y1, rectWidth, rectHeight, blue);
                    canvas.add(blueRect);
                    repaint();
            case "Circle":
                Circle blueCirc = new Circle(x2, y2, circWidth, circHeight, blue);
                canvas.add(blueCirc);
                repaint();
            }//switch end
    }//method end
}); //action listener end

And here's my current Rectangle Class

public Rectangle(int x, int y, int width, int height, Color color) {
    setLocation(x, y);
    setSize(width, height);
    setColor(color);
}
@Override
public void paint(Graphics g) {
    g.setColor(getColor());
    g.fillRect(getX(), getY(), getWidth(), getHeight());
}

My Circle class is the same as my Rectangle class. But when I run the app, only the rectangle shows up and is no longer able to be moved.

Upvotes: 0

Views: 2369

Answers (3)

MadProgrammer
MadProgrammer

Reputation: 347332

  • Start by creating a concept of a "shape", which knows how to paint it self, at a specified location and with a specified color
  • Change your CanvasDrawArea to allow it to accept different instances of this "shape" and repaint itself.
  • Create your JComboBox and place it within the same container as the CanvasDrawArea, but not within it. When the user changes the selection, tell the instance of the CanvasDrawArea to change the shape accordingly...

The core concept is, the CanvasDrawArea is responsible for drawing the shape, that's it. You allow the shape to be changed by some means, via a series of setters and getters, which provides flexibility, but doesn't tie you into a given mechanism (so that the only to change the shape is by triggering an ActionEvent), but allows you to change the way in which the shape changing mechanism works (such as via a random selection, radio buttons or list for example)

For example...

class CanvasDrawArea extends JPanel {
    //...
    private MyShape shape;
    //..
    public void setShape(MyShape shape) {
        this.shape = shape;
        repaint();
    }

    public MyShape getShape() {
        return shape;
    }
    //...
    public void paintComponent(Graphics rect) {
        super.paintComponent(rect);
        MyShape shape = getShape();
        if (shape != null) {
            shape.paint(rect);
        }
    }
}
  • Don't update the state of your component (or any other component) from within any paint method, for example; setBackground(CANVAS_BACKGROUND); is a really bad idea. This will schedule another repaint which could cause the repaint manager to repeatedly repaint your component, consuming your CPU. Instead you should have been setting this values before hand, perhaps in the constructor...

Start by defining the concept of a "shape" and define it's requirements, for example...

public interface MyShape {

    public void setLocation(int x, int y);
    public void setSize(int width, int height);

    public void setColor(Color color);

    public int getX();
    public int getY();

    public int getWidth();
    public int getHeight();

    public Color getColor();

    public void paint(Graphics g);
}

The create the actual implementations, for example...

public abstract class AbstractShape implements MyShape {

    private int x, y;
    private int width, height;
    private Color color;

    @Override
    public void setLocation(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public void setSize(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public int getWidth() {
        return width;
    }

    @Override
    public int getHeight() {
        return height;
    }

    @Override
    public void setColor(Color color) {
        this.color = color;
    }

    @Override
    public int getX() {
        return x;
    }

    @Override
    public int getY() {
        return y;
    }

    @Override
    public Color getColor() {
        return color;
    }

}

public class Rectangle extends AbstractShape {

    public Rectangle() {
    }

    public Rectangle(int x, int y, int width, int height, Color color) {
        setLocation(x, y);
        setSize(width, height);
        setColor(color);
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(getColor());
        g.drawRect(getX(), getY(), getWidth(), getHeight());
    }

}

Where possible, always deal with the interface, this means that when you create more shapes, it will be easier to integrate them

Upvotes: 4

user3918756
user3918756

Reputation:

Well firstly it depends if you want it to change shape automatically or when a action happens. If it's auto for the location set up a TimerTask loop and make a var as the x or y and add to it

int xLoc = 0

Then xLoc = xLoc + 1;

For changing the colour well in your graphics have a int colour = 1; then have if statements if it is 1 set to green if it's 2 blue ect. The way to make this update is to repaint() in your TimerTask

Timer timer = new Timer();

Upvotes: 0

Judah Schvimer
Judah Schvimer

Reputation: 136

Right now it seems like you're just painting and moving the entire canvas rather than moving a shape. In order to change the shape from a rectangle you're going to need to put a shape into your canvas. At that point you can change the shape by swapping in different shape instances.

Using a factory pattern you can get an instance of a new shape just by passing in a string: http://www.oodesign.com/factory-pattern.html

You're then going to also need to keep track of a "current shape" object since the instance will be changing. This will require the proxy pattern to delegate move and color change actions to: http://java.dzone.com/articles/design-patterns-proxy

Upvotes: 0

Related Questions