倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

はじめての幻獣 Griffon 研 (4) : View 〜GUI の構築〜

今回は描画アプリケーションのビューのうち、GUI の構築に関する部分を作成します(一覧)。

ビューの分析


見た目

関数描画アプリケーションの見た目は以下のようなものにします。

アクション

前回定義したアクションはビューの以下の部分から実行できるようにします。

  • paint ・・・ メニューの Action/Paint、NORTH のテキストフィールド、NORTH のボタン
  • about ・・・ メニューの Help/showAbout

モデルのプロパティへのバインド

また、以下のようにモデルのプロパティへバインドを行います。

  • NORTH のテキストフィールド ・・・ model.function
  • WEST のスピナー ・・・ model.max, model.min
  • SOUTH のスピナー ・・・ model.from, model.to

FunctionPlotterView.groovy


では実装。 ソースファイルは前回と同じく

  • FunctionPlotter/griffon-app/views/functionplotter/FunctionPlotterView.groovy

です。 コードは、基本的には『Groovyイン・アクション』 Chapter 8 の関数描画アプリケーションのコードと同じですが、ルートノードとモデルのプロパティへのバインディングの部分が異なります。

package functionplotter

import java.awt.BorderLayout as BL
import javax.swing.WindowConstants as WC
import javax.swing.BorderFactory as BF

actions{
    // action の定義
}

application(title: 'Function Plotter',
  location: [100,100], size: [400,400],
  defaultCloseOperation:WC.EXIT_ON_CLOSE,
  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]) {
    menuBar(){
        menu(mnemonic:'A', 'Action'){
            menuItem(action:paint)
        }
        glue()
        menu(mnemonic:'H', 'Help'){
            menuItem(action:about)
        }
    }

    panel(border:BF.createEmptyBorder(6, 6, 6, 6)){
        borderLayout()
        vbox(constraints: BL.NORTH){
            hbox{
                hstrut(width:10)
                label 'f(x) = '
                textField(action:paint, columns: 20, text: bind(target: model, 'function'), 'sin(x)')
                button(action:paint)
            }
        }
        vbox(constraints: BL.WEST){
            labeledSpinner('max', 1d)
            20.times{ vglue() }
            labeledSpinner('min', -1d)
        }
        vbox(constraints: BL.CENTER, border:BF.createTitledBorder('Function Plot')){
            panel(id:'canvas')
        }
        hbox(constraints: BL.SOUTH){
            hstrut(width:10)
            labeledSpinner('from', 0d)
            10.times{ hglue() }
            labeledSpinner('to', 2d*Math.PI)
        }
    }
}

def labeledSpinner(label, value){
    this.label(label)
    spinner(value:bind(target:model, label), stateChanged:controller.paintGraph, 
                    model:spinnerNumberModel(value:value))
}
  • Griffon では View は application をルートノードとするビルダーで構築します(Java クラスとして作成することもできるようですが)。 Griffon のアイコンも使用できるようです。
  • モデルのプロパティへのバインディングは後述
  • labeledSpinner() メソッドのように、application の GUI を構築するビルダー以外にもメソッドを定義することができます。 このメソッド内で this がさす変数はやはり GUI を構築するビルダーなので、spinner() などで GUI コンポーネントを構築することができます(上記のコードでは label はローカル変数として認識されてしまうので this.label() としています)。

モデルのプロパティへのバインド


バインドを行うには、bind() メソッドを用います。 例えば、textField の text プロパティを model の function プロパティへバインドするためには

textField(text: bind(target: model, 'function'), ...)

とします。 ちなみに、model のプロパティを直接変更しても、その変更はビューへは反映されません。

追記


Model の @Bindable と同様に、Griffon 0.9.1 から View に自動インポートされるようになったパッケージがいくつかあります:

  • java.awt
  • java.awt.event
  • javax.swing
  • javax.swing.event
  • javax.swing.table
  • javax.swing.text
  • javax.swing.tree

Groovyイン・アクション

Groovyイン・アクション