---
keywords: [JRuby, Swing, Java, Ruby]
description: JRubyでのSwingの使用方法や文字コードに関するメモなど
author: aterai
pubdate: 2012-07-19
---
#contents
* Summary [#summary]
- このページは`JRuby`で作成した`Swing`を使用するサンプルの一覧です。
//-- [[JRuby+Swing - てんぷらメモ@はてな>http://d.hatena.ne.jp/aterai/searchdiary?word=%2a%5bJRuby%5d]]から移動。
** 環境変数 [#JRUBY_HOME]
環境変数`JAVA_HOME`, `JRUBY_HOME`を設定し、パスを通しておく。
> set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_04
> set JRUBY_HOME=C:\jruby-1.7.0
> set Path=%JAVA_HOME%\bin;%JRUBY_HOME%\bin;%Path%
> jruby -version
jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM 1.7.0_09-b05 [Windows 7-amd64]
* Swing + JRuby サンプル [#sourcecode]
** EDT で起動(JFrameを表示) [#JFrame]
- `Swing`のコンポーネントは`Event Dispatch Thread`上で扱う必要があるので、以下のサンプルでは、`self`が`java.lang.Runnable`の`run`メソッドを実装し、`java.awt.EventQueue.invokeLater`で実行している
- `require "java"`より`include Java`が良い?
- %%`import`より`java_import javax.swing.JLabel`が良い?%%
- `jruby EDTSwingTest.rb`と実行
#gist(6579373)
** 例外処理の記述方法(SystemLookAndFeelの設定) [#Exception]
- `SystemLookAndFeel`を設定する際の例外処理を、`begin rescue`で記述する
#gist(6579399)
** クラスの継承(JPanelを継承) [#extend]
- `class MainPanel < JPanel`
#gist(6579429)
** 無名インナークラス(JButtonにActionListenerを追加) [#AnonymousClasses]
- リスナーを`JButton`に設定し、クリックすると`JTextField`に文字を追加
-- [http://jira.codehaus.org/browse/JRUBY-903 #JRUBY-903 Java interface modules - jira.codehaus.org]
-- [http://jira.codehaus.org/browse/JRUBY-991 #JRUBY-991 Auto java interface coercion for vanilla ruby objects - jira.codehaus.org]
--- `implicit closure conversion`
-- [http://blog.nicksieger.com/articles/2006/12/01/rspec-jruby-mocking-and-multiple-interfaces RSpec, JRuby, Mocking, and Multiple Interfaces]
-- %%[http://www.bloglines.com/blog/ThomasEEnebo?id=40 Exploring JRuby Syntax Trees in JRuby]%%
-- [https://blogs.oracle.com/nishigaya/entry/tips_for_accessing_java_objects2 Javaインタフェースの実装にクロージャを使用する - Tips for accessing Java objects from JRuby (Part 3) (Nishigaya's Weblog)]
#gist(6579457)
** インタフェースの実装(MouseListenerを追加) [#Interface]
- `java_implements`はもう使用できない?
-- 代わりに: `class MainPanel < JPanel; include MouseListener`
-- カンマ区切りで複数指定しても可: `class MainPanel < JPanel; include MouseListener, ActionListener`
- `instanceof`
-- `self.java_kind_of?(MouseListener)`
#gist(6579526)
** オーバーライドしたメソッドでsuperクラスのメソッドを呼び出すと例外が発生する [#Override]
Exception in thread "AWT-EventQueue-0" org.jruby.exceptions.RaiseException: (NoMethodError) undefined method `paintComponent' for nil:NilClass
- 参考: [http://markmail.org/message/oxpqjwpfo74fdr3j Re jruby-user Error when calling protected method paintComponent in Java Swing superclass - Bill Dortch - org.codehaus.jruby.user - MarkMail]
SuperPaint = JComponent.java_class.declared_method 'paintComponent', 'java.awt.Graphics'
などとして、関数ポインタ?を作成して実行する。
#gist(6579618)
** 配列(JTableに行追加) [#Array]
- `["No.", "Name", "Path"].to_java`で`ruby`の配列を`java`の配列に変換して、`JTable`の行を追加
#gist(6579639)
** protected なメソッドをオーバーライドして使用 [#protected]
- `protected`なメソッドをオーバーライドして使用できなかった
-- `JRuby 1.2.0`で修正?
--- [http://jira.codehaus.org/browse/JRUBY-2861 JRUBY-2861 Cannot call super inside a method that overrides a protected method on Java base class]
- `SwingWorker#process`がオーバーライドして使用(`firePropertyChange`を使用しなくて済む)
//-- https://ateraimemo.com/data/jruby/swing-worker3.rb
- `JDK 1.6.0_18`で、`TableRowSorter`でのソートが不正な件は、`JDK 1.6.0_2x`で修正済
-- `Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: java.lang.Byte cannot be cast to java.lang.Long`
#gist(6590330)
** JRubyでリソース(URL)のエントリを取得してSwingで使用する [#cd7f9169]
- [[JRubyでリソース(URL)のエントリを取得してSwingで使用する>JRuby/Resource]]
** ソースコードの文字コード(エンコーディング) [#encoding]
- `1.7.0`以前?は、`*.rb`の文字コードは`UTF-8`固定だった?
- `1.7.0`から?は、ソースコードの先頭にマジックコメント
-- [http://d.hatena.ne.jp/Artisan/20110409/1302326813 Ruby1.9にしたら invalid multibyte char (US-ASCII) - 屑プログラマの憂鬱]
#code{{
# -*- encoding: utf-8 -*-
include Java
java_import javax.swing.UIManager
java_import javax.swing.WindowConstants
java_import javax.swing.table.DefaultTableModel
def make_ui
p = javax.swing.JPanel.new java.awt.BorderLayout.new
p.add javax.swing.JLabel.new("日本語")
return p
end
def run #Override
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
f = javax.swing.JFrame.new "タイトル"
f.default_close_operation = WindowConstants::EXIT_ON_CLOSE
f.content_pane.add make_ui
f.set_size(320, 240)
f.location_relative_to = nil
f.visible = true
end
java.awt.EventQueue.invoke_later self
}}
* その他、JRuby + One-Liner などのサンプル [#OneLiner]
** JRuby One-Liner で、UIManagerのDefaults.keySetを一覧表示する [#UIManager]
> jruby -rjava -e "javax.swing.UIManager.lookAndFeelDefaults.keySet.each{|o| puts o}"
** One-Liner での文字コード [#CodePoint]
> chcp
現在のコード ページ: 932
> jruby -J-Dfile.encoding=UTF-8 -rjava -e "puts java.net.URLEncoder.encode('日本語','UTF-8')"
> jruby -J-Dfile.encoding=UTF-8 -rjava -e 'puts java.net.URLEncoder.encode(""日本語"",""UTF-8"")'
> jruby --1.9 -U -rjava -e "puts java.net.URLEncoder.encode('日本語','UTF-8')"
> jruby -J-Dfile.encoding=UTF-8 -ruri -e "puts URI.encode('日本語')"
> jruby -ruri -e "puts URI.encode('日本語'.encode('UTF-8'))"
%E6%97%A5%E6%9C%AC%E8%AA%9E
> jruby --1.9 -rjava -e "puts java.net.URLEncoder.encode('日本語','MS932')"
> jruby --1.9 -ruri -e "puts URI.encode_www_form_component('日本語')"
> jruby -ruri -e "puts URI.encode('日本語')"
%93%FA%96%7B%8C%EA
- 参考: [http://jp.rubyist.net/magazine/?0025-Ruby19_m17n Rubyist Magazine - Ruby M17N の設計と実装]
** Unixtimeをiso8601形式の文字列に変換 [#TIME]
> jruby -pe "gsub(/^[0-9]+/) {|x| Time.at(x.to_i)}" cache/recent.dat
2014-09-08 14:31:51 +0900 JRuby/PukiWiki2Markdown
...
> jruby -r time -pe "gsub(/^[0-9]+/) {|x| Time.at(x.to_i).iso8601}" cache/recent.dat
2014-09-08T14:31:51+09:00 JRuby/PukiWiki2Markdown
...
** JRuby 1.7.0.preview1 でArgumentErrorが発生する場合 [#ArgumentError]
- `JRuby 1.7.0.preview1`で以下のような`ArgumentError`が発生する場合、`-J-Dfile.encoding=UTF-8`を指定?
-- `set LANG=ja_JP.UTF-8`は、`JRuby`では効果がない?
-- %% `-J-Dfile.encoding=UTF-8`は`-E UTF-8`と同じ?%%
>jruby -v
jruby 1.7.0 (1.9.3p203) 2012-10-22 ff1ebbe on Java HotSpot(TM) 64-Bit Server VM
1.7.0_09-b05 [Windows 7-amd64]
>chcp
現在のコード ページ: 932
>jruby -J-Dfile.encoding=UTF-8 -ruri -e "puts URI.encode('日本語')"
%E6%97%A5%E6%9C%AC%E8%AA%9E
>jruby -E UTF-8 -ruri -e "puts URI.encode('日本語')"
%93%FA%96%7B%8C%EA
- `JRuby 1.7.0.preview2`では、`-E UTF-8`の方が良さそう
#code{{
lines = src.rstrip.split(/\r?\n/).map {|line| line.chomp }
}}
C:\pukiwiki2markdown>jruby p2m.rb wiki
ArgumentError: invalid byte sequence in Windows-31J
split at org/jruby/RubyString.java:4643
to_html at p2m.rb:45
main at p2m.rb:219
each at org/jruby/RubyArray.java:1611
main at p2m.rb:214
(root) at p2m.rb:234
C:\pukiwiki2markdown>jruby -J-Dfile.encoding=UTF-8 p2m.rb wiki
wiki/2010-04-12-swing-leaftreecelleditor.markdown
wiki/2007-06-18-swing-leftclippedcombobox.markdown
...
C:\pukiwiki2markdown>jruby -E UTF-8 p2m.rb wiki
wiki/2011-07-18-swing-listmouseselection.markdown
...
** JRuby で PukiWiki のファイル名をデコード [#PukiWikiFileName]
- 参考: [http://homepage1.nifty.com/~tetsu/ruby/cmd/ll.html Ruby: ll (ls -l) command (Japanese)]
#code{{
if ARGV[0] == nil then
while line = STDIN.gets
STDOUT.puts "#{line.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')} }"
end
else
Dir::glob("*.#{ARGV[0]}").each {|f|
puts "#{f.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')} }"
}
end
}}
> ls *.txt | jruby decode.rb
> ls *.txt | jruby -pe "$_.gsub!(/[A-F\d]{2}/) {|x| [x.hex].pack('C*')}"
** JRuby で PukiWiki のファイル名にエンコード [#PukiWikiFileEncode]
> jruby -pe 'gsub(/^([0-9]+)\t(.+)$/){[$1,$2.gsub(/./){|x|x.ord.to_s(16).upcase}].join("\t")}' cache/recent.dat
** PukiWiki形式のテキストをMarkdown形式のファイルに変換する [#PukiWikiMarkdown]
[[PukiWiki形式のテキストをMarkdown形式のファイルに変換する>JRuby/PukiWiki2Markdown]]に移動
// ** PukiWiki形式のテキストをWiki形式(Google Project Hosting)のファイルに変換する [#xc0d624b]
// - [[PukiWiki形式のテキストをMarkdown形式のファイルに変換する>JRuby/PukiWiki2Markdown]]を改変して、`PukiWiki`形式のテキストファイルを、`Google Project Hosting`の`Wiki`形式ファイルに変換
//
// jruby -E UTF-8 p2w.rb ./wiki ../java-swing-tips-wiki
//
// - [https://ateraimemo.com/data/jruby/p2w.rb p2w.rb]
// -- https://code.google.com/p/java-swing-tips/w/list
// -- [http://code.google.com/p/support/wiki/WikiSyntax WikiSyntax - support - The reference to the wiki syntax for Google Code projects - User support for Google Project Hosting - Google Project Hosting]
// -- どちらも`Wiki`なので、変換はとても簡単
// -- `ArrowButton`, `BorderFactory`などが自動リンクになってしまう
** PukiWikiのbackupファイルから、公開日時を取得する [#PukiWikiBkup]
- `PukiWiki`の`backup`フォルダ以下にある`.gz`ファイルから、そのファイルの公開日時を取得する
-- 一行目から`Unixtime`を取得しているだけなので、履歴が`$maxage`を超えている場合は不正確になる
#code{{
#!/usr/bin/env ruby
require 'fileutils'
require 'zlib'
require 'time'
#h = Hash.new
path = "/tmp/pukiwiki/backup"
Dir::foreach(path) do |f|
next if f == "." or f == ".." or !f.end_with?(".gz")
ap = "#{path}/#{f}"
Zlib::GzipReader.open(ap) do |gz|
n = f.sub(/\.gz$/, "").gsub(/[A-F\d]{2}/){|x|[x.hex].pack('C*')}
t = gz.gets.sub(/^[>]+ ?[0-9]* /, "") #一行目から日時を取得
x = Time.at(t.to_i).iso8601
puts "#{n}\t#{x}"
#h.store(n, x)
gz.close
end
end
}}
* Reference [#reference]
- [http://www.rubyinside.com/jruby-swt-future-cross-platform-ruby-desktop-app-development-298.html JRuby + SWT = Future Cross Platform Ruby Desktop App Development?]
-- `JRuby` + `SWT`サンプル
-- via [http://www.javalobby.org/java/forums/t84113.html:title=Frankengui? Using SWT and Ruby for your GUIs]
* コメント [#comment]
* Comment [#comment]
#comment
#comment