2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

トップページ | 2011年7月 »

2011年6月の5件の記事

2011年6月28日 (火)

Jruby での「超簡易電卓」

昨日動かしてみた、wxRuby での 「ダイアログ・アプリ」 を Jruby に移植してみます。

include Java

import (<<_AWT).split( ' ' ).map{|c| "java.awt.#{c}"}
   BorderLayout GridLayout
_AWT

import (<<_SWING).split( ' ' ).map{|c| "javax.swing.#{c}"}
  JFrame JPanel
  BoxLayout
  JButton
  JTextField
  Action AbstractAction
_SWING

module WithResource
  module Master
      def regist_resource(r); instance_eval{ @_resource = r }; end
      def ref_resource; instance_eval{ @_resource }; end
  end
  module SlaveExtend
      def new_with_resource(*args)
          resource = args.shift
          a = self.new(*args)
          a.instance_eval{ @_resource = resource }
          a
      end
  end
  module SlaveInclude
      def ref_resource; instance_eval{ @_resource }; end
  end
end

class CalcFrame < JFrame
  include WithResource::Master
  Resource = Struct.new( :display, :pre_val, :sign )

  def initialize( *args )
      super
      text_field = JTextField.new
      regist_resource( Resource.new( text_field, nil, 1 ) )

      pane = get_content_pane
      pane.add( text_field, BorderLayout::NORTH )
      pane.add( create_buttons, BorderLayout::CENTER )
  end

  def create_buttons
      buttons = {}
      10.times do |i|
          action = OnNumber.new_with_resource( ref_resource, i.to_s )
          buttons[ i.to_s ] = JButton.new( action )
      end
      action = OnAC.new_with_resource( ref_resource, 'ac' )
      buttons[ 'AC' ] = JButton.new( action )
      action = OnPlus.new_with_resource( ref_resource, '+' )
      buttons[ '+' ] = JButton.new( action )
      action = OnMinus.new_with_resource( ref_resource, '-' )
      buttons[ '-' ] = JButton.new( action )
      action = OnEqual.new_with_resource( ref_resource, '=' )
      buttons[ '=' ] = JButton.new( action )

      buttons_panel = JPanel.new( GridLayout.new(4,4) )
      %w{7 8 9 AC  4 5 6 +  1 2 3 -  0 x y =}.each do |k|
          if buttons[ k ]
              buttons_panel.add( buttons[ k ] )
          else
              buttons_panel.add( JButton.new( OnNil.new( '' ) ) )
          end
      end
      buttons_panel
  end

  class ProcKey < AbstractAction
      extend WithResource::SlaveExtend
      include WithResource::SlaveInclude
  end

  class OnNil < ProcKey
      def actionPerformed( evt )
      end
  end

  class OnNumber < ProcKey
      def actionPerformed( evt )
          str = ref_resource.display.getText
          str = '' if str == '0'
          str += self.getValue( Action::NAME )
          ref_resource.display.setText( str )
      end
  end

  class OnAC < ProcKey
      def actionPerformed( evt )
          ref_resource.display.setText( '0' )
          ref_resource.pre_val = nil
      end
  end

  class OnPlus < ProcKey
      def actionPerformed( evt )
          ref_resource.pre_val = ref_resource.display.getText.to_i
          ref_resource.sign = 1
          ref_resource.display.setText( '0' )
      end
  end

  class OnMinus < ProcKey
      def actionPerformed( evt )
          ref_resource.pre_val = ref_resource.display.getText.to_i
          ref_resource.sign = -1
          ref_resource.display.setText( '0' )
      end
  end

  class OnEqual < ProcKey
      def actionPerformed( evt )
          if ref_resource.pre_val != nil
              num = ref_resource.pre_val + ref_resource.display.getText.to_i * ref_resource.sign
              ref_resource.display.setText( num.to_s )
              ref_resource.pre_val = nil
          end
    end
  end
end

$top = nil
( $top = CalcFrame.new( 'Calculator' ) ).instance_eval{
  set_default_close_operation( JFrame::EXIT_ON_CLOSE )
  set_size( 200, 220 )
}
$top.visible = true

自力で一から Jruby を書き起こせるほど Swing の event 処理を把握できていないので、Java-GUIプログラミング〈Vol-1〉 で勉強していたときの電卓プログラムを、昨日の wxRuby 版同等まで簡略化してみました。

やっぱり、Jruby で鬱っとおしいのは、Java/Swing の class を個別に import しなければならないこと。

名前空間の collision を避けるために必要であることは理解できるのですが、個別に import を記述するのは大変です。

最初は、%w(...) 記法で列記する形を工夫していましたが、いろいろ試して見た結果、ヒアドキュメントを split するのが一番見た目でわかりやすいようです。

もうひとつ、Java を Ruby に移植するときに困ったのが、class 内で定義した event handler と、親クラスとの間での情報共有です。wxRuby で書くと class をまたがずにすむところをJruby/Swing で書くと、class をまたいでしまうところが ruby で記述しにくくなります。

いくつか試行錯誤を繰り返した結果、こちらも、上記ソースにある、WithResorce という module を親子間で共用することで、共有リソースの扱いを隠蔽できます。

このような工夫をしてみた上で、ソースを比較してみると、やはり wxRuby の方が Jruby よりもソースの行数が少なくすみます。何より見てわかりやすい。また、起動速度の問題も、似たようなプログラムを書いて見ると、wxRuby と Jruby でそれほど差があるようには思えませんでした。

これは、wxRuby で限界にぶつからない限り、wxRuby 優先で学習するべきかもしれません。

2011年6月27日 (月)

sizer を使ってみる - dialog appli

とりあえず、wxRuby を動かせるようになったので、「ダイアログ・アプリ」 のページに進んで、コードを入力しながら使い方を覚えていきます。

wxRuby のことを調べているときに、「sizer がつかいにくい、わかりにくい」という記載が多かったので、結構用心していたのですが、この 「ダイアログ・アプリ」 のページにある程度の規模であれば、そんなに直感に逆らうものではありませんでした。

もちろん、規模が大きくなってくると違うのでしょうが、ruby/tk を書くときも、キーボードから手打ちで packer を使ってレイアウトしたわけですから、別に特段わかりにくい印象はありませんでした。

ボタンに対するイベントの割付は Jruby よりも、wxRuby の方がシンプルでわかり良いように思います。Java は大抵回りくどくて、Jruby で Swing を使っていても、なにか回りくどい。規模がもっと大きくなってきたり、細かなイベントの制御をしようと思えば、そういうことが生きてくるのでしょうが、とりあえず簡単にはじめるにはやはり面倒です。

そのうち、 「ダイアログ・アプリ」 のページ と同等くらいのものを(今自分がわかっている範囲での) Jruby で書いてあげてみようと思いますが、 event を渡す先が自分の method ではなくて、他のクラスの method になってしまうので、Java と ruby の変数スコープの違いから、アプリクラスと event 処理側とで情報を共有するのに工夫がいるのが難点と感じます。たぶん、私がノウハウを知らないだけで、いい方法があるんでしょうが。

逆に Jruby の方がよいことというと、プログラムの起動は Jruby の方が速いように感じました。Jruby 1.6 はすごいです。

2011年6月19日 (日)

wxRuby での日本語表示

この辺は環境依存の問題だと思いますが。

windows XP に mingw32-ruby-1.9.1-wxruby-2.0.1-setup.exe で wxRuby を導入し、wxRubyでGUIプログラミング を順に打ち込んで動作を確認していると、日本語表示がうまくいきません。

「UFT-8 で表示できる」ということで、ファイルを UFT-8 で保存し、command prompt から走らせると、日本語文字列の部分でエラーが出ました。ほかの文字コードではどうかと順に試してみると、JIS で保存すればエラーは出ませんが、画面表示が文字化けします。

ソースで $KCODE = 'U' を指定しても動作に変化なし。

若干あきらめ気味で、最後にコマンドラインオプションで文字コードを指定してみました。

>ruby -KU hello.rb

無事にエラーなく実行でき、画面表示も正常になりました。

【6/19 追記】

もう一度落ち着いて調べなおしてみたら・・・ $KCODE って ruby 1.9 では obsolute だったんですね。勉強不足なだけでした。

wxRuby の環境導入

当面 Jruby と wxRuby を両天秤にかけて、楽な方を選ぼうと思います。で、wxRuby の導入を。

ruby から gem で導入するのもよいのですが、ここはできるだけ安直にいきたいところです。

ここを参照してこちらから(mingw32-ruby-○.○.○-wxruby-○.○.○-setup.exe :○はバージョン)を install します。

(ちなみに、私が download したのは mingw32-ruby-1.9.1-wxruby-2.0.1-setup.exe)

これから「wxRuby で GUI プログラミング」を参照して code を打ち込んでいこうと思います。

ブログ解説のいきさつ - ruby で GUI

趣味でしかプログラムを組まないので、好きなことだけ我流で適当にやっています。意外と windows がいつまでも使い物になるので、まだ当分 windows でやっていくことになりそうですが、いまさら windows でしか使えないプログラムを書く気にもなりません。

もちろんそれだけが理由ではなくて、純粋にいじってて楽しいからなのですが、もう暫く ruby しか触っていません。まあ、大抵テキストフィルタの類しか書かないので、CUI で十分なのですが。

最近 GUI を作りたくなったので、windows に縛られない、ruby で書けるライブラリを調べました。最初は ruby/tk でやってみましたが、jpg file を使うのにてこずって、しかもサムネイルを作ろうとしたら画像の縮小・拡大が簡単にはできそうにないということで、あきらめました。(ちなみに、UNIX で source から入れるならともかく、windows レベルで img 拡張の使える tcl/tk 環境を導入するには、ActiveTcl を入れるのが一番楽そうです)

次に手を出したのが Jruby. いつの間にか十分実用レベルになっているようですし、swing がそのまま使えるのは強い。環境導入も JRE と Jruby を install するだけだから、もし他人に使わせたいようなものができたときにもサポートし易そう。「JRuby 徹底入門」で Java と ruby のすり合わせ方を覚え、「Java GUIプログラミング〈Vol.1〉」を順番に Jruby で実装してみました。

大体なんとかなりそうな手応えをつかみましたが、画面のレイアウトなんかはなんとでもなるとして、Java でのイベント処理を ruby に落とし込むのに若干のノウハウが要りそうです。どこかにまとまった、Jruby で swing な source が落ちてないかと思ったのですが、ある程度の規模のものはなかなか見つかりませんでした。やっぱり情報が少ないですね。

情報を探していると、改めて wxRuby が候補に挙がってきました。レイアウトマネージャーに癖があるようですが、ひとつ魅力なのは、ocra を使えそうなこと。ocra が使えるならば、自作ソフトの配布が楽になります。ですが、これも、tutrial 程度の source は見つかるのですが、まとまった量でイベント処理をこなしている source が見つかりません。

Jruby にせよ、wxRuby にせよ、「これはどうやら、どうやって情報を収拾するかが勝負になりそうだな」と感じたのと、自分で調べたノウハウを保存しておく意味からも、ここらでブログにするのがよいのではないかと考えるに至りました。

というわけなので、このブログの記事が参考になる方はご自由に使っていただくとともに、もっとこんな情報があるよ、という人は是非教えてください。

トップページ | 2011年7月 »