Tom
Tom

Reputation: 8127

JPanel: automatically paint at creation?

This must be rather trivial and straight forward, but I cannot figure it out.

This is what my JPanel looks like, it is added to a JFrame:

private class RadarPanel extends JPanel {       
        public RadarPanel() {
            super();
            this.repaint();
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            //painting logic here

            //repaint in 500 ms
            this.repaint(500);
        }
    }

Now, when I resize the JFrame this JPanel starts getting redrawn all the time. However, when I do not resize the JFrame the JPanel's paintComponent method does not seem to get called, even though I call repaint in the constructor.

Any advice? Thanks.

UPDATE:

more complete code (everything except drawing logic):

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class PlayerRadar extends JFrame {
    private static final long serialVersionUID = 230324190;

    //settings
    private static final int windowWidth = 300;
    private static final int windowHeight = 300;
    private static final int maxDistance = 250;

    //components
    private PlayerRadar radarWindow;
    private JPanel radarPanel;

    public PlayerRadar(String title) {
        super(title);

        //set reference
        radarWindow = this;

        //create radar window
        Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        this.setAlwaysOnTop(true);
        this.setBackground(new Color(0xFFFFFF));
        this.setBounds(screenSize.width - windowWidth, 0, windowWidth, windowHeight);
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                radarWindow.setVisible(false);
            }
        });
        this.setVisible(true);

        //create a JPanel for drawing
        radarPanel = new RadarPanel();
        radarPanel.setBounds(0, 0, windowWidth, windowHeight);
        radarPanel.setBackground(new Color(0xFFFFFF));

        //add to frame
        this.getContentPane().add(radarPanel);
    }

    private class RadarPanel extends JPanel {
        private static final long serialVersionUID = 230324191;
        private static final int repaintInterval = 500;

        public RadarPanel() {
            super();
        }

        @Override
    public void paint(Graphics g) {
        super.paint(g);

        //draw player oval (center of the frame)
        g.setColor(Color.BLUE); //blue
        int ovalWidth = (int) Math.round(this.getWidth() / 30);
        int ovalHeight = (int) Math.round(this.getHeight() / 30);
        int playerLocalX = (int) Math.round(this.getWidth() / 2);
        int playerLocalY = (int) Math.round(this.getHeight() / 2);
        int ovalX = playerLocalX - ovalWidth / 2;
        int ovalY = playerLocalY - ovalHeight / 2;
        g.fillOval(ovalX, ovalY, ovalWidth, ovalHeight);
        g.setColor(Color.BLACK); //black
        g.drawOval(ovalX, ovalY, ovalWidth, ovalHeight);

        //get info of the player itself
        PlayerInfo thisPlayer = GameUtil.getPlayerInfo();
        float playerPosZ = thisPlayer.position[0];
        float playerPosX = thisPlayer.position[2];
        //float playerRotRad = thisPlayer.rotation;

        //set rectangle specs
        int rectWidth = this.getWidth() / 40;
        int rectHeight = this.getWidth() / 40;

        //only continue if we have information about our player
        if (thisPlayer != null) {
            //get nearby players
            ArrayList<PlayerInfo> playersInfo = GameUtil.getNearbyPlayers();

            //for each other player, draw a rectangle
            for (PlayerInfo playerInfo : playersInfo) {                 
                //get data
                float posZ = playerInfo.position[0];
                float posX = playerInfo.position[2];
                //float rotRad = playerInfo.rotation;

                //calculate relative x and y
                int rectX = playerLocalX + Math.round((posX - playerPosX) / maxDistance * this.getWidth() / 2) - rectWidth / 2;
                int rectY = playerLocalY + ovalHeight / 2 + Math.round((playerPosZ - posZ) / maxDistance * this.getHeight() / 2)  - rectHeight / 2;

                //draw rectangle
                g.setColor(Color.RED);
                g.fillRect(rectX, rectY, rectWidth, rectHeight);
                g.setColor(Color.BLACK);
                g.drawRect(rectX, rectY, rectWidth, rectHeight);
            }
        }

        //repaint soon
        this.repaint(repaintInterval);
    }
    }
}

Upvotes: 1

Views: 2369

Answers (2)

camickr
camickr

Reputation: 324147

You where correct the first time. Custom painting is done in the paintComponent() method, NOT the paint() method.

You should NEVER invoke repaint() from within the paintComponent() method, since that will result in an infinite loop.

If you want to animate the painting, then you should be using a Swing Timer to schedule the animation.

You should not be using use setSize(). That is the job of the layout manager. Instead you can override the getPreferredSize() method of the panel (or use setPreferredSize()) and then you can pack() the frame, instead of setting its size.

The panel should be added to the frame BEFORE the frame is made visible otherwise it has a size of (0, 0) which means there is nothing to paint.

Upvotes: 2

m0s
m0s

Reputation: 4280

It won't repaint until your form is shown and graphics is initialized. I don't think calling repaint in constructor is a good idea. It will repaint once the component is visible.

Upvotes: 1

Related Questions