倭マン's BLOG

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

はじめての幻獣 Griffon 研 (27) : マルチ MVC への道 (4) : アプリケーション実行中に MVC グループを作成して埋め込む

今回は、前回と違った MVC グループの埋め込みを見ていきます(一覧)。

今回見ていくのはアプリケーションの実行中に何らかのアクション(例えばボタンを押す)をしたとき、新たにコンポーネントを作成して View に追加するような方法です。 「動的」な埋め込みと言っていいでしょう。

関数描画アプリケーション


「関数描画アプリケーション」では、以下のような操作ができるようにします:





これは以前の記事で見た「同種のビュー(コンポーネント)を複数扱う」場合でもあります。 2つのコンポーネントの違いは関数名(f(x) と g(x))です。

新たに作成されるコンポーネントは、以前作成して前回使った「MonolineFunction」 MVC グループを使い回します。 コード再利用バンザイ! ってことで、今回は「FunctionPlotter」 MVC グループの各要素のコードのみを見ていきます。

  • FunctionPlotterView.groovy
  • FunctionPlotterController.groovy

FunctionPlotterView.groovy


まずは FunctionPlotterView のアクションから。 今回処理を実装するのは 「addFuntion」のみですが、「paintAll」もアクションだけ定義しておきます。

actions{
    action(id:'addFunction',
        name: 'Add Function',
        closure: controller.addFunction,
        mnemonic: 'F',
        accelerator: 'ctrl F')

    action(id:'paintAll',
        name: 'Paint All',
        closure: controller.paintAll,
        mnemonic: 'A',
        accelerator: 'ctrl A')

    ...    // その他の action
}

id や name や Controller の処理などは、名前を揃えておく方が紛らわしくなくていいでしょう。 次に、View の定義は以下のようにします:

package functionplotter

JFrame.defaultLookAndFeelDecorated = true
JDialog.defaultLookAndFeelDecorated = true

actions{ ... }    // 上記のアクション

application(...){
    ...    // メニューバー
    panel(border:emptyBorder(6)){
        migLayout()
        
        panel(id:'controlPanel', constraints:'west', border:emptyBorder(3)){
            migLayout()

            scrollPane{
                panel(id:'functionPanel'){   // MonolineFunction の View が追加されるパネル
                    migLayout(layoutConstraints:'wrap 1')
                    widget(app.views.f.content)
                }
            }
            panel(constraints:'south'){
                button action:addFunction    // MonolineFunction の View を追加するボタン
                button action:paintAll
            }
        }
        ...    // チャート描画部分
    }
}
  • 新たに「MonolineFunction」 MVC グループが作成された場合、その View は functionPanel パネルに追加します。
  • 追加されたパネルが増えた場合に備えて、functionPanel パネルを ScrollPane でラップしています。
  • 「Add Function」ボタンを controlPanel パネルの「south」 に追加します。

FunctionPlotterController.groovy


次は Controller の実装。

package functionplotter

class FunctionPlotterController {

    def model
    def view

    String functionId = 'f'
    private List functionModelList = []    // グラフを描画するときに簡単に参照できるようにするため

    void mvcGroupInit(Map args) {
        createFunctionControl()
    }

    def addFunction = { evt = null ->
        def (m, v, c) = createFunctionControl()
        this.view.functionPanel.add(v.content)
        this.view.controlPanel.updateUI()
    }

    private createFunctionControl(String groupName = 'MonolineFunction'){
        def group = createMVCGroup(groupName, this.functionId, [name:this.functionId+'(x)'])
        this.functionModelList << group[0]    // group[0] は新たに作成された MVC グループの Model
        this.functionId++    // f → g → h → と順々に。
        return group
    }

    def paintAll = { event = null ->
        ...    // 次回やるかも
    }

    ...    // その他の処理
}
  • 関数を追加するのは「addFunction」プロパティですが、MVC グループの生成は前回定義した mvcGroupInit() の処理と同じなので、これは createFunctionControl() メソッドとして抜き出してあります。
  • functionId プロパティは、関数を追加する度に関数名を変えていくために定義しています。 これはまた MVC グループの groupId としても使用しています。
  • functionModelList プロパティは、グラフを描画するときに便利なように定義しています。 今回は特に必要なし。

また、新たな MVC グループのインスタンスを作成したら、次はそれを FunctionPlotterView の functionPanel パネルに埋め込みます:

this.view.functionPanel.add(v.content)

生成した View 自体ではなく、その「content」プロパティの値を add していることに注意。 これは単純に JPanel#add() メソッドを使ったコンポーネントの追加です。 単純に追加しただけでは表示に影響がでないので、適当なコンポーネントをアップデートします:

this.view.controlPanel.updateUI()

これで完了。 まだグラフの描画はできませんが。 これは次回に(予定)。

Griffon in Action

Griffon in Action