groovyの勉強:swingを使ってみた
テキストファイルを読み込んで、指定された行にマッチした行だけを表示するプログラム。
とりあえず、次のことを試してみた。
- JFileChooserのmetaclassを使って、ファイルオープンと保存の処理内容をクロージャで定義して、簡易に読みだすことができるようにしてみた。
- 使えそうな所にbindを使ってみた。
絶賛格闘中のところ。
- クラス内のメソッドからプロパティを書き変えた場合、@Bindableが有効に動いてくれない。なぜ?
感想
- 素のSwingよりは簡単に書けるけど、まだ冗長に見える。もっと省略して色々書けるようにライブラリを整備したい。> Griffon?
- bindingが少し使いづらい。どうせなら、Model->Swingだけでなく、Swing->Model(JTextFieldに文字列を入力すると、モデルに自動で反映させるみたいな)のようなものも簡単に記述できると嬉しい。
- LayoutManagerにForms使いたい。
import java.awt.BorderLayout; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.filechooser.FileNameExtensionFilter import groovy.beans.Bindable; import groovy.swing.SwingBuilder; // JFileChooserに、「ファイルを開くダイアログを開いて、ファイルが選択されたら指定された処理を実行する」メソッドを追加 JFileChooser.metaClass.openFile = { window, action -> if( delegate.showOpenDialog(window) == JFileChooser.APPROVE_OPTION ){ action.call(delegate.getSelectedFile()) } } // JFileChooserに、「ファイル保存ダイアログを開いて、ファイルが選択されたら指定された処理を実行する」メソッドを追加 JFileChooser.metaClass.saveFile = { window, action -> if( delegate.showSaveDialog(window) == JFileChooser.APPROVE_OPTION ){ action.call(delegate.getSelectedFile()) } } // 本プログラムのデータを格納しておくモデル class TextFilterModel { @Bindable File inputFile = null @Bindable String matcher = "" @Bindable String filteredText = "" } // フィルタ処理の定義(TextFilterModel内にメソッド定義するとなぜか動かない。。。) def filter( model ){ if( model.inputFile != null ){ model.filteredText = model.inputFile.filterLine { line -> line =~ model.matcher } } } model = new TextFilterModel() // 以降、画面周りの定義 swing = new SwingBuilder() swing.lookAndFeel("system") chooser = swing.fileChooser( dialogTitle: "Choose Text File.", acceptAllFileFilterUsed: true, fileSelectionMode: JFileChooser.FILES_ONLY, fileFilter: new FileNameExtensionFilter("*.txt", "txt") ) // メインウィンドウの定義 frame = swing.frame( id: 'mainwindow', title: swing.bind(source:model, sourceProperty:'inputFile', converter:{f->"TextFilter ver 0.1 : ${f}"}), defaultCloseOperation: JFrame.EXIT_ON_CLOSE, pack: true, visible: true, ){ // メニューバーの定義 menuBar(){ menu(text: "File"){ menuItem(text: "Open File", actionPerformed: { chooser.openFile(mainwindow){ file -> model.inputFile = file filter(model) } }) menuItem(text: "Save File", actionPerformed: { chooser.saveFile(mainwindow){ file -> file.write(model.filteredText) } }) separator() menuItem(text: "Exit", actionPerformed: {dispose()}) } } // フィルタ用テキストの定義 textField( id: 'matcherField', constraints: BorderLayout.NORTH, actionPerformed: { model.matcher = matcherField.text; filter(model) } ) // フィルタ後テキストの表示領域の定義 scrollPane(constraints: BorderLayout.CENTER){ textArea( columns: 80, rows: 10, editable: false, text: bind(source: model, sourceProperty: 'filteredText') ) } }