概要

以下、JRubyからリソース(URL)のエントリを取得してSwingで使う方法をテストしています。

サンプルコード

# -*- mode:ruby; Encoding:UTF-8 -*-
#module Example
include Java
import java.awt.BorderLayout
class MainPanel < javax.swing.JPanel
  def initialize
    super BorderLayout.new

    ####new javax.swing.ImageIcon("test.png");
    #icon = javax.swing.ImageIcon.new "test.png"
    #icon = javax.swing.ImageIcon.new "./test/test.png"
    #icon = javax.swing.ImageIcon.new ".\\test\\test.png"
    #icon = javax.swing.ImageIcon.new "c:/tmp/test.png"

    #new java.net.URL("https://ateraimemo.com/data/swing/screenshots.png");
    #url = java.net.URL.new "https://ateraimemo.com/data/swing/screenshots.png"
    #url = java.net.URL.new "file:/c:/tmp/test.png"
    #url = java.net.URL.new "file:///c:/tmp/test.png"
    #url = java.net.URL.new "file://localhost/c:/tmp/test.png"

    ####this.getClass().getResource("/test.png");
    url = self.get_class.get_resource "/test.png"
    #url = self.get_class.get_resource "/toolbarButtonGraphics/general/Copy24.gif"
    #url = self.get_class.get_resource "/test.png"

    ####file:/C:/tmp/org/jruby/javasupport/proxy/gen/test.png
    #url = self.get_class.get_resource "test.png"

    ####this.getClass().getClassLoader().getResource("test.png");
    #url = self.get_class.class_loader.get_resource "test.png"
    #url = self.get_class.class_loader.get_resource "toolbarButtonGraphics/general/Copy24.gif"
    #url = self.get_class.class_loader.get_resource "./Example/test.png"

    icon = javax.swing.ImageIcon.new url
    self.add javax.swing.JLabel.new(icon), BorderLayout::CENTER
    self.preferred_size = java.awt.Dimension.new 320, 240
  end
end
#end #module

import javax.swing.UIManager
import javax.swing.WindowConstants
def createAndShowGUI
  begin
    UIManager.look_and_feel = UIManager.system_look_and_feel_class_name
  rescue Exception => e
    proxied_e = JavaUtilities.wrap e.cause
    proxied_e.print_stack_trace
  end
  frame = javax.swing.JFrame.new "jruby swing"
  frame.default_close_operation = WindowConstants::EXIT_ON_CLOSE
  #frame.content_pane.add Example::MainPanel.new
  frame.content_pane.add MainPanel.new
  frame.pack
  frame.location_relative_to = nil
  frame.visible = true
end
class << r = java.lang.Runnable.new
  def run
    createAndShowGUI
  end
end
java.awt.EventQueue.invokeLater r

URLからImageIconを生成

JRubyで、カレントディレクトリにあるリソース(test.png)を使用する場合は、以下のようにファイル名で、SwingImageIconを生成することができます。

#Javaの場合 icon = new javax.swing.ImageIcon("test.png");
icon = javax.swing.ImageIcon.new "test.png"

ImageIconは、URLから生成することも可能です。

url = java.net.URL.new "https://ateraimemo.com/data/swing/screenshots.png"
icon = javax.swing.ImageIcon.new url

位置に依存しない方法でリソースにアクセスしてImageIconを生成

次に、ローカルにあるリソースを使う方法を試してみます。

このとき位置に依存しない方法でリソースへアクセスするため、クラスパスをルートとするエントリでURLを生成します。jruby.batでは、クラスパスに環境変数CLASSPATHを使用するようなので、カレントディレクトリにクラスパスを通し、そこにtest.pngを置いて実行します。

>set CLASSPATH=.
>jruby resources.rb

Class.getResourceメソッドを使う場合、url = this.getClass().getResource("/test.png");と、絶対パス風に先頭に/があればクラスパスをルートにするエントリとみなされます。

#Javaの場合 url = this.getClass().getResource("/test.png");
url = self.get_class.get_resource "/test.png"
icon = javax.swing.ImageIcon.new url
#=> file:/C:/tmp/test.png

JRubyからでも、この方法でリソース(URL)を取得することができました。

  • 注: self.get_class.get_resourcegetを省略不可

jar(zip)アーカイブ内にあるリソースからImageIconを生成

同じ方法で、jar(zip)アーカイブ内にあるリソースを取得する方法を確認します。

クラスパスをjar(zip)アーカイブに通せば、その中にあるリソースへのエントリを与えることで、ディレクトリなどにあるリソースと同様にURLを取得することができます。例えば、Java look and feel Graphics Repositoryにある、jlfgr-1_0.jarをダウンロードして、そのまま展開せずにカレントディレクトリに置き、/toolbarButtonGraphics/general/Copy24.gifを利用します。

まず、jarにクラスパスを通し、

set CLASSPATH=.;jlfgr-1_0.jar

Jarファイルのルートからのエントリ/toolbarButtonGraphics/general/Copy24.gifを与えます。

url = self.get_class.get_resource "/toolbarButtonGraphics/general/Copy24.gif"
#=> jar:file:/C:/tmp/jlfgr-1_0.jar!/toolbarButtonGraphics/general/Copy24.gif

これも特に問題はなさそうです。

他にも、requirejarファイルをクラスパスに追加する(Ruby チュートリアル - 8. JRuby から Java へのアクセス)?方法や

require "jlfgr-1_0.jar"
url = self.get_class.class_loader.get_resource "toolbarButtonGraphics/general/Copy24.gif"

JAR URL構文を使ってエントリを取得する方法(JarURLConnection (Java Platform SE 8))があるようです。

url = java.net.URL.new "jar:file:jlfgr-1_0.jar!/toolbarButtonGraphics/general/Copy24.gif"

位置に依存しない方法でリソースにアクセスしてImageIconを生成2

最後に、url = this.getClass().getResource("test.png");と、相対パス風に先頭に/が無いエントリを与えた場合の方法を試します。

頭に/が無い場合、クラスファイルと同じディレクトリ階層にリソースをおくと便利になるように、getClass().getResource()メソッドは、./に変換された、modified_package_nameが名前(test.png)の前に補完されます。

JRubymoduleなしでクラスを作成し、resources.rbと同じ階層のディレクトリにtest.pngを置いて

url = self.get_class.get_resource "test.png"

としてもnilになります。Rubymoduleを使って別のディレクトリにソースやリソースを移動しても結果は同じです。

どうも、JRubyJavaのクラスが生成される場合、Rubymoduleは考慮せずに、packageorg.jruby.javasupport.proxy.gen固定になっている?ようです。このため、このディレクトリを作成して、/org/jruby/javasupport/proxy/gen/test.pngにリソースをコピーしてから、実行してみると

p self.get_class.name
#=> "org.jruby.javasupport.proxy.gen.JPanel$Proxy0"
url = self.get_class.get_resource "test.png"
#=> file:/C:/tmp/org/jruby/javasupport/proxy/gen/test.png

URLが取得できます。

まとめ

以上、Javaの場合とほとんど同じ方法が使えますが、ローカルにあるシステムリソースを取得したい場合、JRubyでは先頭に/が付いたClassPathからのエントリを使うほうが、すっきりうまくいきそうです。

参考リンク

コメント