2016年07月03日

今RubyでGUIやるならjruby+javafx

俺がこよなく愛している言語はjavascriptとrubyだという話はかなり前から主張してきた
適当な小品を作るにはこいつらで十分だ

ところで、小品といえば近頃WindowsではPowerShellだ。バッチファイルの変態文法に付き合わなくてもいいようになったのですこぶる助かってるんだけど、更に言うとこいつら.NETを自由に呼び出せるんでGUIの小品も作れるんで、かなり重宝してる。例えばゲーム作成のプロトタイピングで画像描画なんかをお手軽にしたい場合とか。

んで、そういうのを手に馴染んだjavascript、rubyでも作ろうとすると簡単にはいかない。ていうかGUIライブラリが標準でついてないんだなこいつらは。



rubyの定番GUIといえば

javascriptはどう考えてもローカルで使うことを考えられてない(HTA+JScriptって選択肢もあるけど)んで、rubyで何か作ろうと思うんだけどrubyってGUIライブラリの定番みたいなのがないんだよね。

いにしえの時代のruby GUIといえばtk、あるいはGtkだったけど、これWindowsで動かすにはどうすればいいんだよ!

最近ではruby/Gnomeとかになってるの?つーかGnomeって3あたりからタブレット前提のインターフェースみたいになってどう扱えばいいかわからなくなったんだけど世の中のみんなはあれについていっているのか

後、昔はvisualurubyっていうのもあった。win32APIのGUI関連ライブラリをrubyから直接叩くという大変漢らしいライブラリ。
これは安定して動く。動かし方も直感的だ。

その他更に昔にはApolloっていうrubyからDelphiのライブラリ叩けるやつがあったんだよ
ああ、懐かしいなDelphi!! ネイティブアプリケーション作れるIDEが無償配布って当時コレしかなかったから必死で覚えたんだよな!
でも今誰がメンテしてるんだろう、もうpascal忘れたなぁ・・・

もっとモダンでQiitaとかでも情報が色々載ってるのはないかな。win32APIではなく.NETを叩けるやつとか。.NET版rubyといえばIronRubyっていう言語があるって聞いたことあるんだけどあれってどうなったんだろう。.NET以外にもGUIのライブラリがついてくる言語環境ないかな、、、あ!

Windows環境のRuby大本命、JRuby

はい、前置き超長かったですね。これだよ。Windowsでネイティブ拡張が安定して動くといえばJRuby。mingw版のオールインワンパッケージ(Rumixとか)より癖のない環境構築できるし、本家とほとんど機能的に変わらない動作と性能なんで、これからWindowsでRuby使うんならJRubyかな、と個人的には思ってる。

んでJavaのGUIライブラリといえば安定のSwing、これをrubyから叩けばお手軽にGUI作れるぜ、と思って色々ネットを調査したら最近はどうも様子が違うらしいですね。
Swingの代わりに現れたRIAを指向したGUIライブラリ、JavaFXが今後のメインストリームになるっていう。
しかもネットで調べるとJRuby+JavaFXってかなり評判いい。これは。。。?

どうなの?JavaFX

あれ?また新しいの覚えなきゃ駄目なの?っていうのが最初に思った率直な感想。
だってSwingって発表当初よりかなり早くなったじゃん。Rubyで書く定番もかなり定まってきたし。
GUI内で任意のテキストを描画したい場合のJRubyのコードはこんな感じだ。

include Java
import javax.swing.JFrame

class Canvas < javax.swing.JPanel
  def paintComponent(g)
    g.draw_string("Hello, Swing", 100, 100)
  end
end

javax.swing.SwingUtilities.invoke_later do
  frame = JFrame.new("Swing JRuby")
  frame.default_close_operation = JFrame::EXIT_ON_CLOSE
  frame.content_pane.add Canvas.new
  frame.setSize(640, 480)
  frame.location_relative_to = nil
  frame.visible = true
end

いいじゃん。かなりRubyっぽい。setXXX(yyy)が xxx=yyyになってるのは気持ちいいし、キャメルクラスをアンダースコアに変えても動作するのも気が利いてる。若干対応しきれない面もあるけど
→setSize(640, 480)みたいに複数引数がある部分はどうしたらいいかわからなかった。
→paintComponentなどのオーバーライド部分はアンダースコア化してpaint_componentにすると親クラスから呼び出してくれなかった

これをjavaFXで書き直すとどうなるか。きっと面倒なことになるんだろうな・・・・

require 'jrubyfx'
include Java

class App < JRubyFX::Application
  def start(stage)
    with(stage, title: "JavaFX JRuby", width: 640, height: 480) do
      canvas = Canvas.new(640, 480)
      gc = canvas.getGraphicsContext2D
      gc.fill_text("hello, JavaFX", 100, 100)
      root = Group.new
      root.children.add(canvas)
      scene = Scene.new(root, 640, 480, Color::WHITE)
      stage.scene = scene
    end.show
  end
end

App.launch


あれ?もっと簡単だ!!つーかJPanelのpaintComponentをオーバーライドとか、SwingUtilities.invokeLaterのスレッドから呼び出し必須とか、EXIT_ON_CLOSEとかsetLocationRelativeToとか気持ち悪いSwingのお約束が一切なくてとってもストレスない!
しかも、これ自由描画欄とテキスト入力とボタンっていうちょっと複雑なコンポーネントの組み合わせを追加しようとすると、SceneBuilderという公式のGUIビルダーを利用することができて

require 'jrubyfx'
require 'jrubyfx-fxmlloader'

fxml_root File.dirname(__FILE__)

class App < JRubyFX::Application
  def start(stage)
    with(stage, title: "FXML JRuby", fxml: MyController) do
    end.show
  end
end

class MyController
  include JRubyFX::Controller
  fxml "fxcanvas.fxml"
end

App.launch

こんなもっと短い行で済む!!!これはお手軽だよ!楽。
※SceneBuilderの生成物fxcanvas.fxmlは実行フォルダに置く
しかもHTML+jsみたいにデザインとコードが分離できてGUIビルダーも用意されててむちゃくちゃ楽!
もうRubyのGUIはこれ一択じゃね?

追記

キャメルクラスのアンダースコア変換はここでもあんまりうまく行ってない部分がある。特にgetGraphicsContext2Dこれ。
一応アンダースコアで呼び出せるんだけどこうなる
graphics_context2_d
なんだよ2_dって
タグ:ruby JRuby
posted by LoyalTouch at 22:07| Comment(0) | TrackBack(0) | クライアントサイド | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.seesaa.jp/tb/439671756

この記事へのトラックバック