0

I am trying to scale an image to fit within a JPanel in my GUI. Whenever I create a new instance of ImagePanel in my JFrame, I get an exception because the width and the height are both 0. However, I overrode getPreferredSize() so it seems like the width and height should be non-zero values.

public class ImagePanel extends JPanel {

private Image image;

public ImagePanel() {
    try {
        image = ImageIO.read(new File("resources/opening.jpg"));
        image = scaleImage(image);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image, 0, 0, this);
}

public void setImage(Image i) {
    image = scaleImage(i);
}

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

public Image scaleImage(Image i) {
    return i.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH);
}
}

Here is the stack trace:

Exception in thread "main" java.lang.IllegalArgumentException: Width (0) and height (0) must be non-zero
at java.awt.image.ReplicateScaleFilter.<init>(ReplicateScaleFilter.java:102)
at java.awt.image.AreaAveragingScaleFilter.<init>(AreaAveragingScaleFilter.java:77)
at java.awt.Image.getScaledInstance(Image.java:172)
at ImagePanel.scaleImage(ImagePanel.java:40)
at ImagePanel.<init>(ImagePanel.java:18)
at GUIFrame.<init>(GUIFrame.java:44)
at main.main(main.java:6)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
tpm900
  • 271
  • 5
  • 11
  • Can you show the stack trace? – MordechayS Nov 21 '16 at 15:06
  • @MordechayS yes, I just added the stack trace – tpm900 Nov 21 '16 at 15:26
  • `getPreferredSize()` is a request, not a guarantee. When you first create the `JPanel`, it's not part of a component hierarchy yet, so it hasn't had an opportunity to be sized. You'll need to call `scaleImage` sometime after the panel has been added to a parent container and laid out. Or you could use the preferred size as the arguments rather than the actual size. – resueman Nov 21 '16 at 15:37

2 Answers2

1

A component doesn't have a size until the panel is displayed in a visible GUI.

So the solution is to do the scaling of your image dynamically in the paintComponent(...) method.

Note you can do this with the drawImage(...) method directly. Read the API there is a method that allows you to specify the width/height of the image as you paint the image.

camickr
  • 321,443
  • 19
  • 166
  • 288
0

From Oracle's docs:

"The pack() method sizes the frame so that all its contents are at or above their preferred sizes..."

So, until you call pack() on your containing JFrame - your components won't have any size except the default one - which is zero.

See these answers for more information:

Community
  • 1
  • 1
MordechayS
  • 1,552
  • 2
  • 19
  • 29