Home > database >  JPanel not rendering correctly, it is taller than the JFrame and things that sould render on top of
JPanel not rendering correctly, it is taller than the JFrame and things that sould render on top of

Time:12-04

When I tell awt/swing to draw a component at a given y that is smaller than the window height, that object renders on the bottom of the bottom border, but it should not, it is supposed to render at that given y.

Here some code example:


    public class Main {
        public static GameWindow window;
        public static void main(String[] args) {
            window = new GameWindow();
        }
    }
    
    class GameWindow extends JFrame {
        private final GamePanel panel;
        public GameWindow() {
            super();
            this.setSize(600, 400); //Observe that the height is 400
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            panel = new GamePanel();
            this.add(panel);
            //Uncomment the following line and observe how the square now renders where it should
            //setUndecorated(true);
            this.setVisible(true);
        }
        //Uncomment the following method to see a black line just on top of the bottom border
        /*@Override
        public int getHeight() {
            return panel.getHeight();
        }*/
    }
    
    class GamePanel extends JPanel {
        public GamePanel() {
            super();
        }
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            //Here it should render just above the bottom border, but it doesn't, it renders well below
            g.fill3DRect(0, Main.window.getHeight() - 22, 22, 22, false);
        }
    }

Case 1: If you live it decorated, you have to resize the window in order to see the square. Case 2: If you make the JFrame undecorated it renders as it should: just on top of the bottom border. Case 3: If you live it decorated, but override the getHeight method so that it returns the height of the panel, a black line is rendered in the bottom of the window.

Images: Case 1: Case 1

Case 2: Case 2

Case 3: Case 3

CodePudding user response:

The coordinate system used by Swing starts in the left upper corner and is relative to the component, and so 0,0 is the left upper part of the JPanel. Here:

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.fill3DRect(0, Main.window.getHeight() - 22, 22, 22, false);
}

You are in fact telling Swing to always draw in a non-visible part of your JPanel, above the JPanel, and so this code will never work.

If you want to draw at the bottom, use component's getHeight() method to find the bottom of the JPanel, and draw above that:

int yPos = getHeight() - 22;
g.fill3DRect(0, yPos, 22, 22, false);

But also, never use "magic numbers" such as 22 here. Also, avoid setting sizes but instead override getPreferredSize():

e.g.,

public class GamePanel extends JPanel {
    public static final int PREF_W = 600;
    public static final int PREF_H = 400;
    public static final int SPRITE_WIDTH = 22;

    public GamePanel() {
        super();
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        int yPos = getHeight() - SPRITE_WIDTH;
        g.fill3DRect(0, yPos, SPRITE_WIDTH, SPRITE_WIDTH, false);
    }

    @Override
    public Dimension getPreferredSize() {
        Dimension superSize = super.getPreferredSize();
        int w = Math.max(PREF_W, superSize.width);
        int h = Math.max(PREF_H, superSize.height);
        return new Dimension(w, h);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            GamePanel mainPanel = new GamePanel();

            JFrame frame = new JFrame("GUI");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }

}

CodePudding user response:

Problem was I was using/overriding JFrame getWidth and Height, I just made a method with another name to get those informations and now it works fine, turns out that returning the panel dimensions in the window methods is not ok.

  • Related