调用setPreferredSize()后,getWidth()和getHeight()为0

时间:2012-02-05 08:35:05

标签: java swing jpanel

我现在已经在我的项目上工作了几个小时,但却一直对此感到沮丧。

我有一个父JFrame,它为它添加了一个JPanel,它将用于渲染和显示我正在开发的模拟。没有将要添加到JPanel的swing对象,因为我将仅使用它来使用图形对象渲染形状。

我的代码如下:

public class SimulationPanel extends JPanel {

private BufferedImage junction;
private Graphics2D graphics;

public SimulationPanel() {
    super();
    initPanel();

}

private void initPanel() {
    this.setPreferredSize(new Dimension(600, 600)); //TODO: bug with not sizing the junction correctly.
    junction = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    graphics = junction.createGraphics();
    setBackground(Color.white);


    System.out.println(getWidth());
}

代码专门在initPanel()方法的第二行中断,我尝试创建一个新的BufferedImage。

异常的输出指出“线程中的异常”AWT-EventQueue-0“java.lang.IllegalArgumentException:Width(0)和height(0)必须是> 0”

我真的不确定这是为什么。我试图使用Stack Overflow的过去的答案,但他们没有成功帮助。

这是我的第一篇文章,所以我希望它不是太糟糕。

感谢。

3 个答案:

答案 0 :(得分:4)

当您设置首选大小时,您可以告诉各种Java布局管理器在将面板添加到容器后,您希望如何布置面板。但是直到它实际上被添加到容器中,它将没有宽度或高度,即使在它之后,它可能没有你要求的宽度和高度。

一个选项是直接使用600作为新缓冲图像的宽度和高度,当您将面板添加到JFrame时,请确保在JFrame上调用pack()以允许窗口大小为您小组的首选尺寸。

答案 1 :(得分:3)

在组件的paintComponent方法中创建一个BufferedImage缓存。在那里,您将知道组件的实际大小,并将其考虑在内以进行渲染。该图像充当组件内容的缓存,但您没有考虑到它的大小是缓存信息的一部分。

@Override protected void paintComponent(Graphics g) {
  // create cache image if necessary
  if (null == image ||
      image.getWidth() != getWidth() ||
      image.getHeight() != getHeight() ||) {
    image = new BufferedImage(getWidth(), getHeight());
    imageIsInvalid = true;
  }

  // render to cache if needed
  if (imageIsInvalid()) {
    renderToImage();
  }

  // redraw component from cache
  // TODO take the clip into account
  g.drawImage(image, 0, 0, null);
}

答案 2 :(得分:1)

这不起作用的原因是pack()未被调用(设置所有宽度和高度值),直到面板启动之后,这就是为什么还没有设置高度和宽度。如果宽度或高度是非正整数,BufferedImage将抛出异常。

那你为什么不自己设定价值呢?以下是如何在您的示例中执行此操作:

private void initPanel() {
    final int width = 600;
    final int height = 600;
    this.setPreferredSize(new Dimension(width, height));
    junction = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
    graphics = junction.createGraphics();
    setBackground(Color.white);
}

或者:如果您要求必须使用组件调整图像大小,则需要。我很确定调用pack()时会触发ComponentListener.componentResized()事件,因此即使您没有调整组件大小,这也应该在您启动组件时起作用。所以请在代码中执行此操作:

private void initPanel() {
    this.setPreferredSize(new Dimension(600, 600));

    this.addComponentListener(new ComponentListener() {

        public void componentResized(ComponentEvent e) {
            Component c = (Component) e.getSource();
            Dimension d = c.getSize();
            resizeImage(d);
        }

    });

    this.setBackground(Color.white);
}

public void resizeImage(Dimension d) {
    junction = new BufferedImage(d.getWidth(), d.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
    graphics = junction.createGraphics();
}