簡體   English   中英

為什么這段顯示圖像的代碼在構建到 jar 中時會給出“錯誤”?

[英]Why does this code displaying an image give an “”error“” when build into jar?

我想通過在 JLabel 上繪制一個 BufferedImage 來顯示它。

x/yOffset 是在 JLabel 的中間繪制一個較小的圖像。

如果我在我的 IDE 中運行代碼,它可以正常工作並在我的 JFrame 上顯示圖像。

如果我現在將類構建到一個 jar 文件中,它就不再起作用了。

我嘗試將 Image 設置為 JLabel 的圖標而不使用 BufferedImage 但這不是我想要做的。

這是我的圖像類的代碼:

public class ImageHQ extends JLabel {

BufferedImage img;

int xOffset=0;
int yOffset=0;


public ImageHQ(String path, int xOffset, int yOffset) {
    try {
        try {
            img = ImageIO.read(new File(getClass().getResource(path).toURI()));
        } catch (URISyntaxException ex) {
            Logger.getLogger(ImageHQ.class.getName()).log(Level.SEVERE, null, ex);
            errorMsg(ex.getMessage());
        }
    } catch (IOException ex) {
        Logger.getLogger(ImageHQ.class.getName()).log(Level.SEVERE, null, ex);
        errorMsg(ex.getMessage());
    }
    
    this.xOffset = xOffset;
    this.yOffset = yOffset;

}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;

    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g.drawImage(img, 0+xOffset, 0+yOffset, null);

    repaint();
}

public void errorMsg(String msg) {
    JOptionPane.showMessageDialog(null, msg, "Fehler", JOptionPane.ERROR_MESSAGE);
}

}

PS:errorMsg 方法也沒有給我一個錯誤。

問題出在這里:

new File(getClass().getResource(path).toURI())

保證應用程序資源是一個單獨的文件。 .jar 條目只是壓縮存檔的一部分。 它不是硬盤驅動器上的單獨文件。 這就是為什么您不能使用 File 來讀取它。

讀取資源的正確方法是根本不嘗試將其轉換為文件。 getResource返回一個 URL; 您可以將該 URL 直接傳遞給采用 URL 的 ImageIO.read 方法

img = ImageIO.read(ImageHQ.class.getResource(path));

請注意使用類文字ImageHQ.class ,而不是 getClass()。 這保證您的資源是相對於您自己的類讀取的,而不是可能位於不同包或不同模塊中的子類。

從 InputStream 讀取

一般來說,可能存在 URL 不夠用的情況。 您還可以使用getResourceAsStream來獲取從資源中讀取的開放 InputStream。 在你的情況下,你可以這樣做:

try (InputStream stream = ImageHQ.class.getResource(path)) {
    img = ImageIO.read(stream);
}

但這不是最佳選擇,因為 URL 可以提供 InputStream 不能提供的信息,例如文件名、內容類型和圖像數據長度的高級知識。

資源路徑

您傳遞給getResourcegetResourceAsStream的 String 參數實際上不是文件名。 它是相對 URL 的路徑部分。 這意味着以C:\\開頭的參數將始終失敗。

因為參數是一個 URL,所以在所有平台上它總是使用正斜杠 ( / ) 來分隔路徑組件。 通常,它是針對調用 getResource* 方法的類對象的包來解析的; 因此,如果ImageHQcom.example包中,則此代碼:

ImageHQ.class.getResource("logo.png")

將在 .jar 文件中查找 com/example/logo.png。

您可以選擇以斜杠開頭 String 參數,這將強制它相對於 .jar 文件的根目錄。 上面的可以寫成:

ImageHQ.class.getResource("/com/example/logo.png")

ClassLoader 中也有 getResource* 方法,但不應使用這些方法。 始終使用 Class.getResource 或 Class.getResourceAsStream 代替。 ClassLoader 方法在 Java 8 及更早版本中在功能上類似,但從 Java 9 開始, Class.getResource 在模塊化程序中更安全,因為它不會與模塊封裝沖突。 (ClassLoader.getResource 不允許/在其 String 參數的開頭,並且始終假定該參數是相對於 .jar 文件的根目錄。)

空返回值

如果路徑參數未命名實際存在於 .jar 文件中的資源(或者如果資源位於不允許讀取的模塊中),則所有 getResource* 方法都將返回null NullPointerException 或 IllegalArgumentException 是這種情況的常見症狀。 例如,如果沒有logo.png與 .jar 文件中的 ImageHQ 類在同一個包中,getResource 將返回 null,並將該 null 傳遞給ImageIO.read將導致 IllegalArgumentException,如 ImageIO.read 文檔中所述.

如果發生這種情況,您可以通過列出其內容來對 .jar 文件進行故障排除。 有多種方法可以做到這一點:

  • 每個 IDE 的文件瀏覽器或文件樹都可以檢查 .jar 文件的內容。
  • 如果您的 JDK 在您的 shell 路徑中,您可以簡單地執行jar tf /path/to/myapplication.jar
  • 在 Unix 和 Linux 中, unzip -v /path/to/myapplication.jar也可以使用,因為 .jar 文件實際上是一個帶有一些 Java 特定條目的 zip 文件。
  • 在 Windows 中,您可以制作 .jar 文件的副本,將副本的擴展名更改為 .zip,然后使用任何 zip 工具(包括 Windows 文件資源管理器)打開它。

回到示例,如果您的類在com.example包中並且您的代碼正在執行ImageHQ.class.getResource("logo.png") ,您將檢查 .jar 文件的內容以獲取com/example/logo.png條目。 如果它不存在,getResource 方法將返回 null。

關於打印錯誤信息

ex.getMessage()替換ex.getMessage() ex.toString() 通常情況下,異常的消息本身是沒有意義的。 您還應該添加ex.printStackTrace(); 到每個catch塊(或添加一個記錄堆棧跟蹤的日志語句),這樣您就可以准確地知道問題發生在哪里。

關於繪畫

永遠不要從paintComponent 方法調用repaint() 這將創建一個無限循環,因為repaint()將強制 Swing 繪畫系統再次調用paintComponent

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM