Java/JavaFX: Set Swing Icon for JavaFX label

2019-06-27 11:15发布

问题:

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!

回答1:

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.



回答2:

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
                         }
                     }
                 }
             });
         }
     }