Search code examples
javaswingdynamicjpaneljcomponent

Can I use getComponents() instead of keeping an ArrayList of components?


I have an app where a user can dynamically add shapes, let's say a Circle (for simplicity), by clicking on a location (x,y). I have been keeping an ArrayList of Circles so they are re-added to the JPanel via the paintComponent() method, however I suspect that this might be redundant given that there is a behind the scenes array being kept, which can be retrieved via the built-in getComponents() method. Am I right? The key parts of my code is below:

public class DrawingPanel extends JPanel implements Constants {
Point point;
Figure figure;

public DrawingPanel() {
    point = new Point(0, 0);
    figure = new Circle(point, defaultSize);
    setLayout(null);
    setBackground(Color.white);
    setPreferredSize(new Dimension(450, 450));
    addMouseListener(new ActionHandler());
}

public void paintComponent(Graphics page) {
    super.paintComponent(page);
    add(figure);
    }

private class ActionHandler extends MouseAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
        super.mousePressed(e);
        Point point = e.getPoint();
        System.out.println("Mouse pressed at (" + e.getX() + ", " + e.getY() + ")");

        String figureState = itemHandler.getFigureState();
        String figureActionState = itemHandler.getFigureActionState();

        if (figureActionState.equals("None")) {
            switch (figureState) {
                case "Circle" -> {
                    figure = new Circle(point, defaultSize);
                    figure.setBounds((int) point.getX(), (int) point.getY(), 50, 50);
                    figure.addMouseListener(new ActionHandler());
                }
                case "Square" -> {
                    figure = new Rect(point, defaultSize);
                    figure.setBounds((int) point.getX(), (int) point.getY(), 50, 50);
                    figure.addMouseListener(new ActionHandler());
                }
                case "Cross" -> {
                    figure = new Cross(point, defaultSize);
                    figure.setBounds((int) point.getX(), (int) point.getY(), 50, 50);
                    figure.addMouseListener(new ActionHandler());
                }
            }
        }
        repaint();
    }
}

}

public class Figure extends JComponent {
Point position;
Dimension size;

public Figure(Point position, Dimension size) {
    this.position = position;
    this.size = size;
}

public void paintComponent(Graphics page) {
    super.paintComponent(page);
}

}

public interface Constants {
ItemHandler itemHandler = new ItemHandler();
Dimension defaultSize = new Dimension(50, 50);

}


Solution

  • You have overall design issues:

    1. A painting method should NOT change the state of the class. The painting method should only paint the current state of the class. Therefore you should NOT be adding components to the panel in the paintComponent() method.

    2. I don't see a reason to keep the two ArrayLists. The component should know how to paint itself and contain all the necessary information to paint itself.

    Maybe instead of using an actual components you can just paint a Shape. Check out Drag a Painted Shape. It keeps an ArrayList of all the Shapes to be painted. This ArrayList is used to identify a Shape that you want to drag. You would need to replace the drag logic with your existing mouse handling logic.