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    
無料ブログはココログ

« sizer を使ってみる - dialog appli | トップページ | NAS 買いました & ワナにかかりました。 »

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 優先で学習するべきかもしれません。

« sizer を使ってみる - dialog appli | トップページ | NAS 買いました & ワナにかかりました。 »

Jruby」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1527616/40578756

この記事へのトラックバック一覧です: Jruby での「超簡易電卓」:

« sizer を使ってみる - dialog appli | トップページ | NAS 買いました & ワナにかかりました。 »