4

I'm trying to read a thumbnail (icon; 32x32px) from a file (.ico/.exe) and set it to a JavaFX label.

My first try:

public Icon getLargeIcon(String exeFile) {
    if (exeFile != null) {
        File file = new File(exeFile);
        try {
            ShellFolder sf = ShellFolder.getShellFolder(file);
            return new ImageIcon(sf.getIcon(true), sf.getFolderType());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    return null;
}

After that I'm doing this:

    Icon largeIcon = getLargeIcon(file.getAbsolutePath());
    ImageIcon swingImageIcon = (ImageIcon) largeIcon;
    java.awt.Image awtImage = swingImageIcon.getImage();
    Image fxImage = javafx.scene.image.Image.impl_fromPlatformImage(awtImage);
    lblAppIconValue.setGraphic(new ImageView(fxImage));

I've searched trough several sites and found this, but it gives me an exception: java.lang.UnsupportedOperationException: unsupported class for loadPlatformImage

My second try:

            URL url = file.toURI().toURL();
            Image image = new Image(url.toString());
            lblAppIconValue.setGraphic(new ImageView(image));

Also not working ...

My question: How can I set a javax.swing.Icon to a JavaFX label? Is it possible? If it's not possible, how can I read a thumbnail from a file and set it as an icon/graphic for a JavaFX label?

Thanks!

baris1892
  • 981
  • 1
  • 16
  • 29

2 Answers2

5

Never use impl_ methods: these are not part of the public API.

To convert an awt Image to an FX Image, the SwingFXUtils class in javafx.embed.swing has a toFXImage(...) method that converts a BufferedImage to a JavaFX Image. It's not clear whether the image you have from the icon is a BufferedImage, so you'll need a couple of steps to make that work:

BufferedImage bImg ;
if (awtImage instanceof BufferedImage) {
    bImg = (BufferedImage) awtImage ;
} else {
    bImg = new BufferedImage(awtImage.getWidth(null), awtImage.getHeight(null), BufferedImage.TYPE_INT_ARGB);
    Graphics2D graphics = bImg.createGraphics();
    graphics.drawImage(awtImage, 0, 0, null);
    graphics.dispose();
}
Image fxImage = SwingFXUtils.toFXImage(bImg, null);

This is a fairly inefficient approach, as you are first creating an awt image from your file, then converting it to an FX image, possibly via an intermediate buffered image. If you have access to the source code for the ShellFolder class, you might see how that implements the getIcon() method and follow the same process. At some point, it must get an InputStream with the image data; once you have that you can pass it to the javafx.scene.image.Image constructor.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • I got an error on that line: graphics.drawImage(0, 0, awtImage); "The method drawImage(Image, int, int, ImageObserver) in the type Graphics is not applicable for the arguments (int, int, Image)" – baris1892 Oct 04 '14 at 14:05
  • Oops, sorry, remembered the parameters incorrectly. I fixed it now. – James_D Oct 04 '14 at 14:07
  • 1
    I’m not sure whether someone who uses `sun.awt.shell.ShellFolder` cares about whether `impl_` methods are not part of the JavaFX public API. After all, it’s consequent to use non-standard APIs on *both* sides. By the way, if an `Image` is not a `BufferedImage` and you use `drawImage` with a `null` observer and ignore its return value, there is no guaranty that the `Image` is complete (or if anything has been drawn at all)… – Holger Nov 03 '14 at 16:19
  • @Holger The OP didn't show imports, so I wasn't aware of what `ShellFolder` was; both your points are good ones. – James_D Nov 03 '14 at 16:28
0

If you want to place an image in your application on JavaFX you have 2 main options:

  1. Define it in fxml:

    <ImageView>
      <Image url="icon.png"/>
    </ImageView>
    
  2. Create Label in your controller:

    import javafx.scene.control.Label;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    
    ...
    
    Image image = new Image(getClass().getResourceAsStream("icon.png"));
    Label label = new Label("Label");
    label.setGraphic(new ImageView(image));
    

icon.png should be placed in the same package with fxml-file or your controller (otherwise you should amend image name in that example).

Update: change image in label dynamically (in accordance with image selected by user).

fxml:

    <Button fx:id="setImageButton"/>
    <ImageView fx:id="image">
        <Image url="defaultImage.png"/>
    </ImageView>

Controller:

     public class MainController implements Initializable {
         public Parent root;
         public Button setImageButton;
         public ImageView image;

         @Override
         public void initialize(URL location, ResourceBundle resources) {

             setImageButton.setOnAction(new EventHandler<ActionEvent>() {
                 @Override
                 public void handle(ActionEvent event) {
                     FileChooser fileChooser = new FileChooser();
                     File file = fileChooser.showOpenDialog(root.getScene().getWindow());
                     if (file != null) {
                         try {
                             BufferedImage bufferedImage = ImageIO.read(file);
                             Image picture = SwingFXUtils.toFXImage(bufferedImage, null);
                             image.setImage(picture);
                         } catch (IOException ex) {
                             // do something
                         }
                     }
                 }
             });
         }
     }
anlar
  • 477
  • 1
  • 11
  • 26
  • the problem is, that the icon should change dynamically, because the user can pick an exe file, e.g. "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" – baris1892 Oct 04 '14 at 13:56
  • thanks, but it's still not working, I get all the time a NullPointerException at line "bufferedImage = ImageIO.read(file);" (file is not null!) – baris1892 Oct 04 '14 at 16:08