倭マン's BLOG

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

はじめての幻獣 Griffon 研 (29) : マルチ MVC への道 (6) : アプリケーション実行中に MVC グループを破棄する destroyMVCGroup / mvcGroupDestroy

以前の記事で新たに MVC グループを生成する方法を見ましたが、今回はその逆に、既に存在する MVC グループを破棄する方法を見ていきます(一覧)。

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


関数描画アプリケーションに組み込む機能としては、各 functionPanel パネル(関数式を入力する部分)にボタンをつけて、クリックするとそのパネルが削除されるようにします:







メッセージ・ダイアログは mvcGroupDestroy() メソッドの使い方のために(無理矢理)入れているだけです。 機能としては不必要*1

コードを追加する(リ)ソースは以下のものです:

  • FunctionPlotter/griffon-app/views/functionplotter/MonolineFunctionView.groovy
  • FunctionPlotter/griffon-app/resources/function/remove.png
  • FunctionPlotter/griffon-app/controllers/functionplotter/MonolineFunctionController.groovy
  • FunctionPlotter/griffon-app/controllers/functionplotter/FunctionPlotterContoller.groovy

MonolineFunctionView.groovy


まずは MonolineFunctionView。 これに施す変更は

  • 関数を削除する「Remove」アクションの追加
  • 「Remove」アクションのトリガーとなる「Remove」ボタンの配置

です。 これらはまぁ、普通の View の実装です:

package functionplotter

actions{
    action(id:'remove',
        name: 'Remove',
        closure: controller.remove)
}

panel(id:'content', border:titledBorder(title:'Groovy')){
    migLayout()

    toolBar(constraints:'north'){
        this.button action:remove, hideActionText:true, icon:imageIcon('/function/remove.png')
    }

    label text: bind{ model.name }
    label '='
    textField 'sin(x)', columns:15, action:paint, text: bind(target:model, 'function')
}
  • 「Remove」ボタンはツールバーに作成してみました。 アイコンの設定はアクションにした方がいい気もしますが、イマイチ動かなかったので「Remove」ボタンの位置にて設定。
  • アイコンの画像は「FunctionPlotter/griffon-app/resources/function/remove.png」に配置。 アイコンはこんな感じに作成 →

MonolineFunctionController.groovy


さて次は、先ほど定義した「Remove」アクションの処理を Controller に実装しましょう(もちろん MonolineFunctionController)。

ここでの処理で、対象となっている「MonolineFunction」 MVC グループのインスタンスを破棄したいのですが

  • FunctionPlotterController の functionModelList フィールドから、破棄したい MVC グループの Model を削除する
  • FunctionPlotterView の functionPanel パネルから 、破棄したい MVC グループの View を削除する

という処理が必要なので、「Remove」処理は FunctionPlotterController に投げることにしましょう。 処理を投げるメソッドは removeFunction() とします(後ほど実装)。

package functionplotter

import javax.swing.JOptionPane

class MonolineFunctionController {

    def model
    def view
    String mvcName

    def remove = { evt = null ->
        app.controllers.FunctionPlotter.removeFunction(mvcName)
    }

    void mvcGroupDestroy(){
        JOptionPane.showMessageDialog(app.windowManager.windows[0],
                                      "Function $mvcName(x) is removed.")
    }
}
  • mvcName プロパティは、この MVC グループを生成したときに指定した groupId です(createMVCGroup() メソッドに渡した第2引数 )。 これは、破棄する MVC グループを特定するために、FunctionPlotterController#removeFunction() メソッドに引数として渡します。 ちなみに、この mvcName プロパティは値が自動で注入されます*2
  • FunctionPlotterController オブジェクトは、「app.controllers.FunctionPlotter」によって取得しています。 「FunctionPlotter」MVC グループは1つしかインスタンスがないので、これでも取得できます。
  • mvcGroupDestroy() は、この MVC グループが破棄される際に呼ばれます(mvcGroupInit() と対照的)。 ここでは、削除された関数の名前を表示しています。

FunctionPlotterController.groovy


最後は MVC グループの破棄を行う FunctionPlotterController#removeFunction() メソッドの実装。 最後に destroyMVCGroup() メソッドを呼び出して MVC グループを破棄します。 一度破棄するとそのグループのメンバを参照できないので、その前に不必要な参照を削除しておきます:

package functionplotter

class FunctionPlotterController {

    def model
    def view

    private List functionModelList = [] as LinkedList

    def removeFunction(String mvcName){
        def group = app.groups[mvcName]
        if(!group)return

        // Model を削除
        this.functionModelList.remove(group.model)

        // View を削除
        this.view.with{
            functionPanel.remove(group.view.content)
            controlPanel.updateUI()
        }

        // MVC グループを破棄
        destroyMVCGroup(mvcName)
    }
}
  • mvcName (MVC グループの groupId)から、MVC グループを取得するためには「app.groups[mvcName]」とします。 この返り値は MVC グループのメンバを含んだ Map オブジェクトになっていて、'model', 'view', 'controller', 'builder' をキーに、グループのメンバにアクセスできます。
  • destroyMVCGroup() メソッドの引数には MVC グループの groupId を指定します(「関数描画アプリケーション」の例では 'f' や 'g' など)。 'MonolineFunction' などの名前ではありません。

これにて破棄処理の実装は完了。 removeFunction() メソッドの最後に destroyMVCGroup() メソッドを呼ばなくても実際には動きますが、2度と使用されない MVC グループのインスタンスがメモリ上に残ったままになるので好ましくありません。 いらない MVC グループはきちんと破棄しましょう。

Griffon in Action

Griffon in Action

*1:というより、アプリケーション自体を終了すると、残っている functionPanel パネルの個数だけダイアログが表示されて鬱陶しくなります ^ ^;)

*2:はじめての幻獣 Griffon 研 (26) : マルチ MVC への道 (3) : アプリケーション開始時に MVC グループを作成し、ビューを埋め込む createMVCGroup / mvcGroupInit」参照。