【问题标题】:Java: how to add image references properly from a non-src folderJava:如何从非 src 文件夹中正确添加图像引用
【发布时间】:2022-08-04 11:07:08
【问题描述】:

它又是关于 VSCode 和 Java 的(我开始学习它)。我有一个小测试程序,可以加载图像并且在 VSCode IDE 中启动时可以正常工作。我还在这里看到我必须以某种方式从“类路径”加载图片 - 所以我为屏幕截图中显示的“图片”文件夹添加了一个类路径。

我看到图片已加载到 jar 中,但在运行时找不到它们(可能是因为子文件夹或因为它们不在 src 中 - 但我当然希望将它们放在单独的文件夹中)。还可以在屏幕截图中查看源代码 - 我应该如何更好地让 jar 正常工作,而且还可以在 IDE 中测试代码?目前我喜欢这样:

PicLabel pl1 = new PicLabel(new File(
                \"./pics/Screenshot from 2022-07-20 15-40-16.png\"));

my folder setup

    标签: java image resources


    【解决方案1】:

    new File 是字面意思。它的意思是文件.物理上,在磁盘上。此外,. 表示“当前工作目录”,即用户启动 java 进程的目录是什么,即谁知道 - 你不能依赖它是任何特定的,因此,这段代码注定要失败。它永远行不通。 (或者更确切地说,它仅在用户遵循信中的说明并且用户不那样工作时才有效)。

    鉴于 Java 应用程序是作为 jar 分发的,您希望图像成为这些 jar 中的条目。它们不是文件,因此new File 表示您丢失了。

    正确的做法是使用MyClass.class.getResource("/pics/Screenshot.png")

    这将为您提供一个 URL,您可以将其传递给例如ImageIcon 之类的。我不知道 PicLabel 是什么,但它可能需要一个 URL。如果没有,则有:

    try (InputStream in = MyClass.class.getResource("/pics/Screenshot.png") {
      // use 'in' here
    }
    
    • 如果不使用 URL,则使用 InputStream。如果这也不可能,那就是一个愚蠢的 API;停止使用它,而是找到一个未损坏的库。

    这将与YourClass.class 所在的位置相同。即使它在一个罐子里。即使当前的工作目录不是您认为的那样。将/pics/Screenshot.png 粘贴在罐子内,上面的行将“找到”它。

    【讨论】:

    • 不好意思见上
    • 看什么?我注意到您编辑了您的问题;据我所知,我的回答与更新一样正确。
    • 我的意思是查看我的“自己的答案”以获取更多详细信息。我发现自己回答很奇怪,只是为了添加一个格式化的代码——但我会学习的。最后,我会按照你的建议去做,不要尝试按照我的方式使用文件夹,即使我觉得它很有用...... :-)
    【解决方案2】:

    好的,谢谢,我按照你的例子做了一些测试(PicLabel 只是我自己的帮助类,它给我一个格式化的 JLabel,里面有一个图片和一个框架):

    当我在 src 下创建一个文件夹“picccs”时,我可以访问那里的资源图片(b.png)。但问题仍然是 - 是否也可以将它放在 src 旁边的 pics 文件夹中(见上面的截图),a.png 在哪里? (在那里我得到 null 作为 URL):

    try {
        URL in_b = Gui.class.getResource("/picccs/b.png");  
        URL in_a = Gui.class.getResource("/pics/a.png");  
    } catch (Exception e) {
        //TODO: handle exception
    }
    

    【讨论】:

    • 抱歉,我是新来的,我无法用代码 sn-p 评论您的建议.. ?
    • 这个问题取决于您的构建工具和 IDE 配置。答案是:是的,你可以这样做。使用“正常”项目设置,java 源代码位于 src/main/java,而这些 png 将位于 src/resources。 (例如,如果你使用 maven)
    【解决方案3】:

    我喜欢将 .png 文件放在资源文件夹中,然后使用 getResource 加载它们,如前所述。项目结构应该使用标准的 Maven/Gradle 配置:

    -- root/
      -- app/
        -- src/
          -- main/
            -- java/
              -- my.package.name/ (java files go here)
            -- resources/
              -- image/ (image files go here)
    

    当项目构建时,resources 目录的内容将被添加到类路径并可供加载。

    就个人而言,我喜欢创建一个实现singleton 模式的java 类,这样我可以多次引用图像,但它们只加载一次(操作成本高)。假设我在resources/image 文件夹中有三个图像,image_one.png、image_two.png、image_three.png,我打算与JLabel 对象一起使用。那么我的班级可能看起来像这样:

    public class ImageLib {
    
        // single reference to ImageLib
        private ImageLib INSTANCE;
    
        // member for each image I want to use
        private ImageIcon imageOne;
        private ImageIcon imageTwo;
        private ImageIcon imageThree;
    
        // private constructor for singleton pattern
        private ImageLib() {
            imageOne = loadImageIcon("image/image_one.png"
            imageTwo = loadImageIcon("image/image_two.png"
            imageThree = loadImageIcon("image/image_three.png"
        }
    
        // static method to get the single instance
        public static ImageLib getInstance() {
            if (Objects.isNull(INSTANCE) {
                INSTANCE = new ImageLib();
            }
            return INSTANCE;
        }
    
        public ImageIcon getImageOne() {
            return imageOne;
        }
    
        public ImageIcon getImageTwo() {
            return imageTwo;
        }
    
        public ImageIcon getImageThree() {
            return imageThree;
        }
    
        // helper method to load .png into ImageIcon
        private ImageIcon loadImageIcon(String path) throws RuntimeException {
            try {
                URL url = getClass().getClassLoader().getResource(path);
                return new ImageIcon(url);
            } catch (NullPointerException e) {
                throw new RuntimeException(String.format("Failed to load image: %s", path));
            }
        {
    }
    

    现在我们可以多次从ImageLib 类中以ImageIcon 的形式获取.png,但它只会加载一次。比如我们可以创建多个JLabel对象并设置图标:

    ImageLib images = ImageLib.getInstance();
    
    JLabel labelOne = new JLabel("some message");
    labelOne.setIcon(images.getImageOne());
    
    JLabel labelTwo = new JLabel("some message");
    labelTwo.setIcon(images.getImageOne());
    

    【讨论】:

      猜你喜欢
      • 2014-08-02
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 2018-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多