2

I have created a custom JButton where override the setIcon.

public class TestButton extends JButton {

    public TestButton() {
        super();
    }

    @Override
    public void setIcon(Icon icon) {
        super.setIcon(icon);
        imgToBufferedImg(Toolkit.getDefaultToolkit().createImage("test.png"));
    }
}

And here is the imgToBufferedImg method.

public BufferedImage imgToBufferedImg(Image image) {
    if (image == null) {
        return null;
    }
    if (image instanceof BufferedImage) {
        return ((BufferedImage) image);
    } else {
        BufferedImage bufferedImage = new BufferedImage(
                image.getWidth(null),
                image.getHeight(null),
                BufferedImage.TYPE_INT_ARGB);

        Graphics g = bufferedImage.createGraphics();
        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bufferedImage;
    }
}

I have added this component in Matisse, no problem, however, when i try to set the icon property of the button i get the error:

Failed to write the value to the property "icon"

The problem seems to come from the imgToBufferedImg since i can set the property if i remove the call to this method in setIcon. What is wrong with my image conversion method?

EDIT:

The following test succeeded:

try {
    imgToBufferedImg(ImageIO.read(new FileInputStream("test.png")));
} catch (IOException ex) {
    Exceptions.printStackTrace(ex);
}

Also i just figured out that the problem is caused by:

((ImageIcon) icon).getImage();

Running this code when the UI is ready (e.g using a SwingUtilities.invokeLater) seems to work.

nathan
  • 1,111
  • 3
  • 18
  • 33

3 Answers3

3

The problem might be in Toolkit#createImage(). ImageIO.read() might be better. Also, it looks like you're throwing away the result from imgToBufferedImg().

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
Catalina Island
  • 7,027
  • 2
  • 23
  • 42
  • It does not look like, i'm throwing away the result. I tried a make this test case as simple as possible to show that the only fact to call my method raise the problem. In my actual project, i do thinks differently of course, the code you can see in my question is the result of a code refactoring a target the problem. I don't think the problem comes from Toolkit since it's supposed to return an Image from a path as String. – nathan Oct 08 '12 at 13:18
  • @nathan: `Toolkit` "operations may be performed asynchronously." Your `Image` may be incomplete when you try to render it. `ImageIO.read()` is worth a try. – trashgod Oct 08 '12 at 17:22
2

no reason why

  • create BufferedImage inside JButtons setIcon(), there you would be to set (for JButton) Icon, ImageIcon

  • this BufferedImage (should be Icon, ImageIcon) is create after is added to JButton


but

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • not sure to understand. Actually the code i show was a test case and i need to load images regarding the icon set. So i need to call this code each time a new icon is set. Actually, i fill an array of ImageIcon containing post-effected icons. – nathan Oct 08 '12 at 08:52
  • `post-effected icons` in `JButtons API` are impelemented a fwe methods for `setXxxIcon` directly, or to use [ButtonModel](http://stackoverflow.com/questions/5751311/creating-a-custom-button-in-java-with-jbutton/5755124#5755124) , maybe there any reason to override `JButton` ... – mKorbel Oct 08 '12 at 09:02
  • :-) matisse call one method. setIcon. i'd like to call my logic from this method. I'm aware of those methods and i use them but after executing the logic within setIcon. My question is why my method imgToBufferedImg cause the mentioned error. – nathan Oct 08 '12 at 09:07
1

Thanks to the thrashed comment:

Toolkit "operations may be performed asynchronously." Your Image may be incomplete when you try to render it.

I was able to figure out what the problem was. Straight from the setIcon method, i requested the image from the icon:

((ImageIcon) icon).getImage()

But this image is definitively incomplete. Putin my logic within the event dispatching thread did the trick.

SwingUtilities.invokeLater(new Runnable() {

    @Override
    public void run() {
        //requesting icon images here
    }
}
nathan
  • 1,111
  • 3
  • 18
  • 33