Bernhard's Weblog - Groovy SwingBuilder FormLayout

いちいちGroovy起動すんのにコマンドプロンプト開くのもアレだし,どうせならGUIでも作ろうかなぁと思ってみれば,Swingってよく知らないやという罠が。:-P
そんな自分のスキルを棚に上げ,今さらSwing(というかMetal L&F)ってのも味気ないし,どうせGroovyだし(?)なんて意味があるんだか無いんだかわからん理由をこねてJGoodiesに手を出してみた。
#実際,FormLayout使いやすいし。


そこで見つけたのが,このエントリのリンク先。まんまFormLayoutの使い方を載せてくれているのがありがたい。
この人,intの二次元配列で苦労していたようだけど,Groovy1.5で試してみたら,こんなコードですんなり動いたよ。

    layout.columnGroups = [[1, 5], [3, 7]] as int[][];

EDTまわりは,そもそもSwingのEDT(Event Dispatch Thread)をよくわかってないんで,なんとも言えない。ただ,内部クラスや無名クラスが使えないかわりにクロージャ使うってのは分かった。
#今のSwingBuilderみると,.edt(Closure)とか.doLater(Closure)とかあるね。
#→Groovy 1.5の新機能


あと気になったのが,イベントリスナの張り方。これは,InfoQの記事にサンプルが書いてあった(これもまたクロージャ)。
「GroovyMarkupは,なんちゃってメソッドとクロージャのかたまりなんだ」って念仏唱えて挑まないと,GroovyMarkupのコードはギョっとするね。

def textlabel
def frame = swing.frame(title:'Frame', size:[300,300]) {
  borderLayout()
  textlabel = label(text:"Clicked ${count} time(s).",
                    constraints: BL.NORTH)
  button(text:'Click Me',
         actionPerformed: {
           count++
           textlabel.text = "Clicked ${count} time(s)."
         }, constraints:BorderLayout.SOUTH)
}

ちなみに,元のリンク先のちょこちょこ弄ったコードがこれ。

import groovy.swing.SwingBuilder
import javax.swing.WindowConstants
import javax.swing.JFrame
import javax.swing.UIManager

import com.jgoodies.forms.factories.Borders
import com.jgoodies.forms.layout.CellConstraints
import com.jgoodies.forms.layout.FormLayout
import com.jgoodies.forms.factories.DefaultComponentFactory
import com.jgoodies.looks.plastic.*

class SampleMainSwing3 {
  JFrame frame
  def value1, value2

  static void main( String[] args ) {
//    UIManager.lookAndFeel = UIManager.systemLookAndFeelClassName
    UIManager.lookAndFeel = Plastic3DLookAndFeel.class.name

    SampleMainSwing3 sms = new SampleMainSwing3()
    sms.frame.show()
  }

  public SampleMainSwing3() {
    initComponents()
    frame.pack()
  }

  private void initComponents() {
    FormLayout layout = new FormLayout(
        "right:pref, 3dlu, pref:grow, 7dlu, right:pref, 3dlu, pref:grow", // columns
        "p, 3dlu, p, 3dlu, p, 9dlu, p, 3dlu, p, 3dlu, p")      // rows


    // Specify that columns 1 & 5 as well as 3 & 7 have equal widths.
    layout.columnGroups = [[1, 5], [3, 7]] as int[][]

    // Obtain a reusable constraints object to place components in the grid.
    final CellConstraints cc = new CellConstraints()

    // create instance of DefaultComponentFactory for creating separators
    final def dcf = DefaultComponentFactory.instance

    def swingB = new SwingBuilder()
    frame = swingB.frame(title: 'Groovy FormLayout Swing GUI',
                         defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) {
      panel(layout: layout, border: Borders.DIALOG_BORDER) {
        //
        widget(widget: dcf.createSeparator('General'), constraints: cc.xyw(1, 1, 7))
        label("Company", constraints: cc.xy(1, 3))
        textField("companyField",constraints: cc.xyw(3, 3, 5))
        label("Contact", constraints: cc.xy (1, 5))
        textField("contactField", constraints: cc.xyw(3, 5, 5))

        widget(widget: dcf.createSeparator('Propeller'), constraints: cc.xyw(1, 7, 7))
        label("value1", constraints: cc.xy (1, 9))
        value1 = textField("value1",constraints: cc.xy(3, 9))
        label("JButton ->", constraints: cc.xy(5, 9))
        button("Button", constraints: cc.xy(7, 9), actionPerformed:{actionButton()})
        label("value2", constraints: cc.xy(1, 11))
        value2 = textField("value2",constraints: cc.xy(3, 11))
        label("GButton ->",constraints: cc.xy(5, 11))
        textField("diameterField",constraints: cc.xy(7, 11))
      }
    }
  }

  void actionButton() {
    value2.text = value1.text.toUpperCase()
  }
}