简体   繁体   English

JPanel 渲染不正确,它比 JFrame 高,应该渲染在底部边框顶部的东西渲染在它下面

[英]JPanel not rendering correctly, it is taller than the JFrame and things that sould render on top of the bottom border render below it

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.当我告诉 awt/swing 在小于 window 高度的给定 y 处绘制组件时,object 呈现在底部边框的底部,但它不应该呈现在给定的 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.情况1:如果你住的是装修过的,你必须调整window的大小才能看到正方形。 Case 2: If you make the JFrame undecorated it renders as it should: just on top of the bottom border.情况 2:如果您使 JFrame 未修饰,它会按应有的方式呈现:就在底部边框的顶部。 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.情况 3:如果您对其进行了装饰,但覆盖了 getHeight 方法,使其返回面板的高度,则在 window 的底部呈现一条黑线。

Images: Case 1:图片:案例 1: 情况1

Case 2:案例二: 案例二

Case 3:案例三: 案例三

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. Swing 使用的坐标系从左上角开始并且是相对于组件的,因此 0,0 是 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.实际上,您是在告诉 Swing 始终在 JPanel 上方的 JPanel 不可见部分中绘制,因此此代码永远不会起作用。

If you want to draw at the bottom, use component's getHeight() method to find the bottom of the JPanel, and draw above that:如果要在底部绘制,请使用组件的getHeight()方法找到 JPanel 的底部,然后在其上方绘制:

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

But also, never use "magic numbers" such as 22 here.而且,永远不要在这里使用诸如22之类的“幻数”。 Also, avoid setting sizes but instead override getPreferredSize() :此外,避免设置大小,而是覆盖getPreferredSize()

eg,例如,

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);
        });
    }

}

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.问题是我正在使用/覆盖 JFrame getWidth 和 Height,我只是用另一个名称创建了一个方法来获取这些信息,现在它工作正常,事实证明在 window 方法中返回面板尺寸是不正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM