What is it, naokirin?

Groovy初心者がGriffonを試してみた

どうも、先日Ruby合宿に行ってきたのに、早速Groovyやってるnaokirinです。

前々からやってみたいと思っていたGriffonを触ってみたので、ブログに書き残しておこうと思います。

まずはGriffonのプロジェクトを作る

もちろん、Griffonのインストールは済んでるとして話を進めます。

その上でGriffonのアプリケーションを作成するために、プロジェクトを作成します。
コンソールで

griffon create-app helloworld

と打つとプロジェクトが作成されます。

今回はプロジェクト名(アプリケーション名)をhelloworldにしました。

とりあえず実行してみる

とりあえず、プロジェクト作成時にすでに最低限のMVCのコードが準備されているので、実行してみます。

まずプロジェクトのルートに移動します。

cd helloworld

次にデスクトップ・アプリとして実行してみます。

griffon run-app

これによって、デスクトップアプリケーションが実行されます。

これ以外にもAppletやJava Web Startとして実行できるようです。

ソースコードを確認してみる

プロジェクトのルートディレクトリで

cat griffon-app/models/helloworld/HelloworldModel.groovy

を実行してみます。

package helloworld

import groovy.beans.Bindable

class HelloworldModel {
   // @Bindable String propName
}

これがModel-View-ControllのうちのModelにあたるソースコードです。今回はこのModel部分は扱いません。


次にView部分です。

cat griffon-app/models/helloworld/HelloworldModel.groovy
package helloworld

application(title: 'helloworld',
  preferredSize: [320, 240],
  pack: true,
  //location: [50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]) {
    // add content here
    label('Content Goes Here') // delete me
}

Viewには最初、labelが一つだけ入っています。これが最初に実行した際に表示されていたものです。


最後にControll部分です。

cat griffon-app/controllers/hellowrold/HelloworldController.groovy
package helloworld

class HelloworldController {
    // these will be injected by Griffon
    def model
    def view

    // void mvcGroupInit(Map args) {
    //    // this method is called after model and view are injected
    // }

    // void mvcGroupDestroy() {
    //    // this method is called when the group is destroyed
    // }

    /*
        Remember that actions will be called outside of the UI thread
        by default. You can change this setting of course.
        Please read chapter 9 of the Griffon Guide to know more.
       
    def action = { evt = null ->
    }
    */
}

ここまで確認してみたところで、実際にModel-View-Controllに関係するソースコードはgriffon-appというディレクトリの下にあることがわかったと思います。

実際に作ってみる(View編)

今回は、最初「helloworld」と表示していて、ボタンを押すと「Goodbye」に切り替わるという簡単なものです。

まず、Viewを書き換えます。

package helloworld

application(title: 'helloworld',
  preferredSize: [320, 240],
  pack: true,
  //location: [50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]) {
  // add content here

  panel{
    borderLayout()
    vbox {
      hbox{
        label(id:'hellolabel', text:'helloworld')
      }
      hbox{
        button()
      }
    }
  }
}

ラベル、ボタンを追加しています。

panel{
  borderLayout()
  vbox {
    hbox{
      // idを設定することで、後でこのラベルのテキストを
      // Controllerで変更できるようにする
      label(id:'hellolabel', text:'helloworld')
    }
    hbox{
      button()
    }
  }
}

これで、「helloworld」のラベルとボタンが表示されるアプリケーションができました。

これだけでは寂しいので、ボタンを押すとラベルのテキストが変更されるようにしてみます。


そのために、「action」というものを使います。

Viewには既に「application」というノードが存在していますが、「actions」というノードをViewに追加します。

package helloworld

// 追加したアクション
actions {
  action(id:'goodbye',
    name:'Goodbye',
    closure: controller.showGoodbye,
    mnemonic: 'G',
    accelarator: 'ctrl G')
}

// applicationのノード
// ...

実際にこのアクションの処理というのは「controllers.showGoodbye」で記述するつもりです。なのでそうなるように定義しています。実際に処理を記述している部分を「closure」という部分で指定しています。それ以外の部分もみればわかると思いますので詳しい説明は省きます。


さて、実際にこのアクションの処理を書く前に、ボタンを押したらアクションを実行するようにしておきましょう。

// ...
hbox{
  // ボタンにアクションを定義
  button(action:goodbye)
}

このように書けばボタンを押した際に、アクションで定義された処理が実行されます。


ここまででViewは終わったので、最後に最終的なViewのソースコードをのせます。

package helloworld

actions {
  action(id:'goodbye',
    name:'Goodbye',
    closure: controller.showGoodbye,
    mnemonic: 'G',
    accelarator: 'ctrl G')
}

application(title: 'helloworld',
  preferredSize: [320, 240],
  pack: true,
  //location: [50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]) {
  // add content here
  // label('Content Goes Here') // delete me

  panel{
    borderLayout()
    vbox {
      hbox{
        label(id:'hellolabel', text:'helloworld')
      }
      hbox{
        button(action:goodbye)
      }
    }
  }
}

実際に作ってみる(Controller編)

アクションを定義したから、Controllerでちゃんとそのアクションの処理を書いておきましょう。

class HelloworldController {
    // these will be injected by Griffon
    def model
    def view

    // ラベルを「Goodbye」に書き換えるアクションの処理
    def showGoodbye = { evt = null ->
      def label = view.hellolabel

      label.setText('Goodbye')
    }
}

ここで、

def label = view.hellolabel

の部分について詳しく説明します。

まず、

// these will be injected by Griffon
def model
def view

は、それぞれModelやViewに紐づいているので、これらの変数を通して、ModelやViewにアクセスできます。

つぎにViewを書いていた時に

label(id:'hellolabel', text:'helloworld')

と書いていたことを思い出しましょう。
idに'hellolabel'としていたので、このラベルにアクセスする場合には

view.hellolabel

のように書くことでアクセスできます。


これで、今回の仕様を満たすアプリケーションを作成できました。

最初にやったように

griffon run-app

を実行して、ボタンを押して「Goodbye」に切り替わるか試してみましょう。