【问题标题】:Java/JavaFX: Set Swing Icon for JavaFX labelJava/JavaFX:为 JavaFX 标签设置 Swing 图标
【发布时间】:2014-10-04 12:30:16
【问题描述】:

我正在尝试从文件 (.ico/.exe) 中读取缩略图(图标;32x32px)并将其设置为 JavaFX 标签。

我的第一次尝试:

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

之后我会这样做:

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

我搜索了几个网站并找到了这个,但它给了我一个例外: java.lang.UnsupportedOperationException: unsupported class for loadPlatformImage

我的第二次尝试:

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

也不行……

我的问题:如何将 javax.swing.Icon 设置为 JavaFX 标签?是否可以?如果不可能,如何从文件中读取缩略图并将其设置为 JavaFX 标签的图标/图形?

谢谢!

【问题讨论】:

    标签: java javafx icons label


    【解决方案1】:

    永远不要使用 impl_ 方法:这些不是公共 API 的一部分。

    要将 awt 图像转换为 FX 图像,javafx.embed.swing 中的 SwingFXUtils 类具有将 BufferedImage 转换为 JavaFX ImagetoFXImage(...) 方法。目前尚不清楚您从图标中获得的图像是否为BufferedImage,因此您需要几个步骤来完成这项工作:

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

    这是一种相当低效的方法,因为您首先从文件创建 awt 图像,然后将其转换为 FX 图像,可能通过中间缓冲图像。如果您有权访问 ShellFolder 类的源代码,您可能会看到它如何实现 getIcon() 方法并遵循相同的过程。在某些时候,它必须获得带有图像数据的InputStream;一旦你有了它,你就可以将它传递给javafx.scene.image.Image 构造函数。

    【讨论】:

    • 我在该行出现错误:graphics.drawImage(0, 0, awtImage); "Graphics 类型中的 drawImage(Image, int, int, ImageObserver) 方法不适用于参数 (int, int, Image)”
    • 糟糕,抱歉,记错了参数。我现在修好了。
    • 我不确定使用sun.awt.shell.ShellFolder 的人是否关心impl_ 方法是否不是JavaFX 公共API 的一部分。毕竟,在双方上都使用了非标准的API。顺便说一句,如果Image 不是BufferedImage 并且您将drawImagenull 观察者一起使用并忽略它的返回值,则无法保证Image 是完整的(或者如果已经完全绘制)...
    • @Holger OP 没有显示导入,所以我不知道 ShellFolder 是什么;你的两个观点都很好。
    【解决方案2】:

    如果您想在 JavaFX 上的应用程序中放置图像,您有两个主要选项:

    1. 在 fxml 中定义:

      <ImageView>
        <Image url="icon.png"/>
      </ImageView>
      
    2. 在你的控制器中创建Label

      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 应该与 fxml-file 或您的控制器放在同一个包中(否则您应该在该示例中修改图像名称)。

    更新:动态更改标签中的图像(根据用户选择的图像)。

    fxml:

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

    控制器:

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

    【讨论】:

    • 问题是,图标应该动态变化,因为用户可以选择一个exe文件,例如"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    • 谢谢,但它仍然无法正常工作,我总是在 "bufferedImage = ImageIO.read(file);" 行收到 NullPointerException (文件不为空!)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 2014-01-26
    相关资源
    最近更新 更多