JROS
JROS

Reputation: 17

Why is my Component repainted over and over without any changes happening?

I have a beginner Swing/AWT question for you.

I am doing custom painting of a BoxPanel Object that extends JPanel. I have n of these BoxPanels that are then drawn in a JFrame called FormSolutionViewer using a FlowLayout. Now the issue I am having is that after the JFrame is created and made visible, it is repainted in an infinite loop, without any changes happening to the components. Can someone explain to me why this is and how to fix it so that it only gets repainted when the window is resized or some of the data actually changes?

public class BoxPanel extends JPanel {

    private Box box;
    private int scaleFactor;

    public BoxPanel(Box box, int scaleFactor) {
        super();
        this.box = box;
        this.scaleFactor = scaleFactor;
        this.setLayout(null);   // Use null layout for absolute positioning
    }

    /**
     * Need to override getPreferredSize() when using a FlowLayout
     */
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(this.box.getLength() * this.scaleFactor, this.box.getLength() * this.scaleFactor);
    }

    /**
     * Paint the box border, background and its rectangles
     * @param g
     */
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        this.setBackground(Color.white);

        // Display no. of rectangles contained in tooltip
        this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");

        // Draw border of box
        this.setBorder(BorderFactory.createLineBorder(Color.black));

        /* Draw rectangles contained in box */
        int i = 1;
        for (Rectangle rect : box.getRectangles()) {
            System.out.println("Rectangle " + i + ": " + rect.toString());

            g.setColor(Color.BLACK); // Set color for border
            g.drawRect(rect.getPos().getX() * this.scaleFactor, rect.getPos().getY() * this.scaleFactor, 
                    rect.getWidth() * this.scaleFactor, rect.getHeight() * this.scaleFactor);               
            i++;
        }

    }
}


public class FormSolutionViewer extends JFrame {

    private JPanel contentPane;
    private FeasibleSolution solution;

    int scaleFactor = 40;
    int spacing = 5;

    /**
     * Create the frame.
     */
    public FormSolutionViewer(FeasibleSolution solution, int x, int y, int dpi) {
        this.solution = solution;

        this.scaleFactor = (int) Math.round(dpi / 2.4);

        setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        setBounds(x, y, 800, 600);
        setTitle("Initialized Solution of " + solution.getInstance().toString());
        this.setBackground(new Color(250, 250, 250));

        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(spacing, spacing, spacing, spacing));

        FlowLayout layout = new FlowLayout(FlowLayout.LEADING, 5, 5);
        contentPane.setLayout(layout);
        this.setContentPane(contentPane);

        /* Place the boxes */
        int boxNo = 0;
        int rowCount = 0;
        for (Box box : solution.getBoxes()) {
            boxNo++;

            BoxPanel boxPanel = new BoxPanel(box, scaleFactor);
            contentPane.add(boxPanel);
            contentPane.setSize(this.getWidth(), 500); 
            boxPanel.setVisible(true);
        }
    }
}

Upvotes: 0

Views: 42

Answers (1)

camickr
camickr

Reputation: 324098

this.setBackground(Color.white);
...
this.setToolTipText("Box contains " + this.box.getRectangles().size() + " rectangles");
...
this.setBorder(BorderFactory.createLineBorder(Color.black));

Don't set a property of the component in the painting method. When a property of a component is changed, Swing invokes revalidate()/repaint() on the component to reflect the new state of the component.

The point of a painting method is to paint the component in its current state, not change its state.

Upvotes: 1

Related Questions