【问题标题】:Why is JPanel size is wrong?为什么 JPanel 大小不对?
【发布时间】:2021-02-10 23:48:29
【问题描述】:

有扩展JFrame的类的构造函数:

import java.awt.*;
import javax.swing.*;

public class ChessFrame extends JFrame {
    public ChessFrame () {
        setSize(520, 520);
        setResizable(false);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new GridLayout(1, 1));

        // Add components
        getContentPane().add(new Board());
        pack();
        setVisible(true);
    }
}

以及扩展 JPanel 的类:

import javax.swing.*;

public class Board extends JPanel {
    public Board() {
        setSize(new Dimension(520, 520));
    }

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

        g.fillRect(0, 0, 520, 520);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(520, 520);
    }
}

因此矩形小于 520x520。

黑色矩形的大小约为 496x510。还有更多:

  1. getWidth()getHegiht() 写在 Board 类中,返回 0 和 0(所以这个 JPanel 在 JFrame 中的大小是 0x0)
  2. 如果我删除pack(),框架大小变为496x510(黑色矩形大小)

其实是官方java教程的copypaste:https://docs.oracle.com/javase/tutorial/uiswing/painting/step2.html

我做错了什么还是与java有关?如果是第二个,为什么会这样? 任何帮助将不胜感激。

【问题讨论】:

  • 面板和框架的尺寸永远不会相同。框架大小包括标题栏和边框。不要尝试设置框架(或 JPanel)的大小。您只需要像您所做的那样覆盖getPreferredSize()。在您的绘画方法中,不要在绘画矩形时对值进行硬编码。相反,您可以使用 getWidth() 和 getHeight()。
  • @camickr, 之后有覆盖getPreferredSize(),调用pack()和frame setVisible()。
  • 请注意,在框架被打包或可见之前,组件没有大小,所以是的,在您的类的构造函数中,您将看到大小为 0。paintComponent( ) 方法。如果上述解释没有意义,请发布适当的minimal reproducible example 来演示问题。您可能有其他逻辑导致问题。此外,无需进行自定义绘画。您可以只使用 setBackground(...) 方法来填充面板的背景颜色。
  • @camickr 我现在明白为什么它返回 0 和 0,非常感谢。我使它可重现(除了在 SwingUtilities.invokeLater() 的帮助下从另一个类调用 JFrame 构造函数)。谢谢!
  • 我之前说过您不需要面板的 setSize()。也不需要扩展 JFrame。启动应用程序的 main() 方法只需要创建一个 JFrame 实例并将 Board 组件添加到框架中。您说您从 Swing 教程中复制了代码,但您的代码结构与教程中的示例不同。正确的minimal reproducible example 将包含演示问题所需的所有代码。

标签: java swing jframe jpanel


【解决方案1】:

此示例仅在框架(和面板)在屏幕上可见时尝试确定面板大小。它返回代码中设置的确切大小(300 像素)。

import java.awt.*;
import javax.swing.*;

public class ChessBoard extends JPanel {
    
    int size = 300;
    JLabel sizeLabel = new JLabel();

    ChessBoard() {
        setBackground(Color.CYAN);
        setLayout(new GridBagLayout());
        add(sizeLabel);
    }
    
    public void showSize() {
        sizeLabel.setText(String.format("%1sx%1s", getWidth(), getHeight()));
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(size,size);
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            ChessBoard cb = new ChessBoard();
            
            JFrame f = new JFrame(cb.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);
            
            f.setContentPane(cb);
            f.pack();
            f.setMinimumSize(f.getSize());
            
            f.setVisible(true);
            // delay showing size until app. is on-screen
            Runnable r1 = cb::showSize;
            SwingUtilities.invokeLater(r1);
        };
        SwingUtilities.invokeLater(r);
    }
}

【讨论】:

  • 非常感谢,它有效,这是一个很好的起点!
  • 不客气。给定“国际象棋”这个名字,我只是想起了其他可能感兴趣的东西。另见Making a robust, resizable Swing Chess GUI
  • 再次感谢您,您是对的,我现在正在尝试解决这个问题 =) @Andrew Thompson
  • 好吧,我猜你很幸运,因为my answer 中的 215 行代码生成了问题中的屏幕截图。 ;) 玩得开心! :)
猜你喜欢
  • 2011-04-22
  • 1970-01-01
  • 2019-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
相关资源
最近更新 更多