GridBagLayout没有调整图像加载大小

时间:2015-09-21 05:15:03

标签: java swing layout-manager bufferedimage gridbaglayout

我有一个JFrame。它使用JPanel作为其内容窗格,并且JPanel使用GridBagLayout作为其LayoutManager。 JPanel还包含两个项目:一个按钮和另一个JPanel。在程序启动时,使用ImageIO.read(...)将图像从文件加载到最低级别的JPanel作为BufferedImage。这就是一切都要崩溃的地方。

图像正确加载,我可以在屏幕上看到它的一个小角(调试器中指定的14px正方形)。我无法弄清楚是什么导致布局增长并使整个图像适合屏幕上最低级别的JPanel。调试器中的图像显示正确的500px大小。 CardImagePanel的首选大小正确显示为与图像大小相同。但是除非我使用setSize(...)手动设置CardImagePanel大小,否则布局将不会考虑首选大小,我很确定GBL不应该这样做。

我已经尝试在整个程序中对每个JFrame,JPanel,布局,网格包,图像等进行revalidate()和repaint()调用,但是找不到正确的地点或时间来调用它们来制作这件事有用。目前我一直试图让图像加载错误并使用按钮强制重新验证和重新绘制,但即使这个显式调用也没有做任何事情。

我正在失去理智,我会做任何事来让这件事发挥作用。

以下是我所有愚蠢事情的代码(减去导入和包规范。

P1s1.java:

public class P1s1 {

    public static void main(String[] args) {
        // TODO code application logic here
        build();
    }

    public static void build()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(new Dimension(640, 480));
        frame.setContentPane(new GuiPanel(frame));
        frame.setVisible(true);
    }
}

GuiPanel.java:

public class GuiPanel extends JPanel {

    JFrame parentFrame;
    JButton imageLoaderButton;
    CardImagePanel cardImagePanel;
    LayoutManager layout;
    GridBagLayout gridBagLayout;
    GridBagConstraints constraints;

    public GuiPanel(JFrame frame)
    {
        parentFrame = frame;

        constraints = new GridBagConstraints();
        gridBagLayout = new GridBagLayout();

        layout = gridBagLayout;
        this.setLayout(layout);

        this.setBorder(BorderFactory.createLineBorder(Color.black));

        setupImageLoaderButton(imageLoaderButton);

        cardImagePanel = new CardImagePanel();
        this.add(cardImagePanel);
    }

    private void setupImageLoaderButton(JButton button)
    {
        button = new JButton("Click to load image!");
        ActionListener imageLoaderListener;
        imageLoaderListener = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent ae) {
                System.out.println("Button clicked.");

                cardImagePanel.revalidate();
                cardImagePanel.repaint();

                GuiPanel.this.revalidate();
                GuiPanel.this.repaint();

                parentFrame.revalidate();
                parentFrame.repaint();
            }
        };
        button.addActionListener(imageLoaderListener);
        this.add(button);
    }
}

CardImagePanel.java:

public class CardImagePanel extends JPanel {

    BufferedImage cardImage;

    public CardImagePanel()
    {
        this.setBorder(BorderFactory.createLineBorder(Color.black));

        try {
            cardImage = ImageIO.read(new File("c:\\dev\\cards\\2_of_clubs.png"));
            this.setPreferredSize(new Dimension(cardImage.getWidth(), cardImage.getHeight()));
        } catch (IOException ex) {
            System.out.println("Exception trying to load image file.");
        }
    }

    // The getPreferredSize() override was suggested by MadProgrammer.
    // It did not solve the issue, but see MadProgrammer's updated,
    // accepted answer below for the correct solution.  The rest of the
    // code reflects my original attempt to solve the issue.
    @Override
    public Dimension getPreferredSize()
    {
        return cardImage != null ? new Dimension(cardImage.getWidth(), cardImage.getHeight()) : super.getPreferredImage();
    }

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

        g.drawImage(cardImage, 0, 0, this);
    }
}

2 个答案:

答案 0 :(得分:3)

您的CardImagePanel没有首选尺寸,因此布局管理员不知道如何正确处理尺寸。

一些解决方案:

  1. 无需创建自定义类来显示图像。只需使用JLabel即可显示图像。 JLabel将返回图像的首选大小。
  2. 如果您使用CardImagePane,则需要覆盖CardImagePanel的getPreferredsize()方法以返回图像的大小。

答案 1 :(得分:3)

GridBagLayout依赖于一个组件来告诉它它想要的大小(以及当它被释放时它的最小和最大大小)。您需要覆盖getPreferredSize的{​​{1}}方法,返回您希望组件的大小

CardImagePanel

有关详细信息,请查看How to Use GridBagLayout