単純なプログラムを書換えよう(Groovy編)−クラスを作ってみる

java編のオリジナルソースに近い形でクラスを定義してみた.前回のソースとの違いは以下の通りである.

  • ファイル名とクラス名は同一
  • 全体をclass Viewで囲む
  • 表示する値を入れるラベルvalueをクラスViewのインスタンス変数にする.これがないと,コンストラクタの中のローカル変数となるのでactionメソッドからアクセスできない
  • static void mainメソッドの追加
//View.groovy
import groovy.swing.SwingBuilder
import java.awt.BorderLayout

class View{
  value //actionメソッドで使えるようにvalueをインスタンス変数とする

  View(){
    builder=new SwingBuilder()
    view=builder.frame(defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE,
                       size:[200,100]){
      panel(layout:new BorderLayout()){
        value=label(text:"0",constraints:BorderLayout.CENTER)
        panel(constraints:BorderLayout.SOUTH) {
          button(text:'inc', actionPerformed:{action(it)})
          button(text:'dec', actionPerformed:{action(it)})
        }
      }
    }
    view.show()
  }
  
  void action(event){
    actions=['inc':{value.text=Integer.toString(value.text.toInteger()+1)},
             'dec':{value.text=Integer.toString(value.text.toInteger()-1)}]
    actions[event.actionCommand]()
  }

  static void main(args){ //追加
    new View()
  }
}
//end
  

java編のオリジナルソースにあわせてMainクラスとViewクラスを分けて作成しよう.

//View.groovy
import groovy.swing.SwingBuilder
import java.awt.BorderLayout

class View{
  value

  View(){
    builder=new SwingBuilder()
    view=builder.frame(defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE,
                       size:[200,100]){
      panel(layout:new BorderLayout()){
        value=label(text:"0",constraints:BorderLayout.CENTER)
        panel(constraints:BorderLayout.SOUTH) {
          button(text:'inc', actionPerformed:{action(it)})
          button(text:'dec', actionPerformed:{action(it)})
        }
      }
    }
    view.show()
  }
  
  action(event){
    actions=['inc':{value.text=Integer.toString(value.text.toInteger()+1)},
             'dec':{value.text=Integer.toString(value.text.toInteger()-1)}]
    actions[event.actionCommand]()
  }
}
//end

//Main.groovy
class Main{
  static void main(args){
    view=new View()
  }
}
//end
  

ViewをActionListenerにして,イベントリスナを使おうとするとエラーになる.エラーメッセージを見ると,addActionListenerの引数がActionListerではなくてClosureになっているためのようなのだが,ClosuerをActionListenerにキャストする方法も良く分からないのでこれ以上は追跡しない.

//View.groovy
import groovy.swing.SwingBuilder
import java.awt.event.ActionEvent
import java.awt.event.ActionListener
import java.awt.BorderLayout

class View implements ActionListener{
  value

  View(){
    builder=new SwingBuilder()
    view=builder.frame(defaultCloseOperation:javax.swing.WindowConstants.EXIT_ON_CLOSE,
                       size:[200,100]){
      panel(layout:new BorderLayout()){
        value=label(text:"0",constraints:BorderLayout.CENTER)
        panel(constraints:BorderLayout.SOUTH){
          button(text:'inc',addActionListener:this) イベントリスナを登録
          button(text:'dec',addActionListener:this) イベントリスナを登録
        }
      }
    }
    view.show()
  }
  
  void actionPerformed(ActionEvent event){
    actions=['inc':{value.text=Integer.toString(value.text.toInteger()+1)},
             'dec':{value.text=Integer.toString(value.text.toInteger()-1)}]
    actions[event.actionCommand]()
  }
}
//end
  
$ groovy View.groovy
Caught: groovy.lang.MissingMethodException: No signature of method javax.swing.J
Button.addActionListener() is applicable for argument types: (View$_closure1_clo
sure4_closure5) values: [View$_closure1_closure4_closure5@2f1921]
        at View$_closure1_closure4_closure5.doCall(c:\Documents and Settings\sat
oshi\My Documents\groovy\View.groovy)
        at View$_closure1_closure4.doCall(c:\Documents and Settings\satoshi\My D
ocuments\groovy\View.groovy)
        at View$_closure1.doCall(c:\Documents and Settings\satoshi\My Documents\
groovy\View.groovy)
        at View.<init>(c:\Documents and Settings\satoshi\My Documents\groovy\Vie
w.groovy)
        at View.main(c:\Documents and Settings\satoshi\My Documents\groovy\View.
groovy)