ScalaSwingを使ってみた

めでたく、2.7.2.finalもリリースされたことなので、
ScalaSwingを使ってみた。

サンプルを参考に
任意のファイルを、指定して何らかの処理をするツールのGUI部分だけを書き直した。

import java.io._
import swing._
import swing.event._
import javax.swing._

object SsConverterGUI extends SimpleGUIApplication {
  // ----------------------------------------------------
  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName)
  val chooser = new FileChooser(new File("."))

  // ----------------------------------------------------
  object fileSelectBtn extends Button { text = "ファイル選択" }
  object goBtn extends Button { text = "実行" }

  // ----------------------------------------------------
  object textfield extends TextField {
    columns = 30
    text = DefaultFile
    
    listenTo(fileSelectBtn)
    reactions += {
      case ButtonClicked(button) if (button == fileSelectBtn) =>
        chooser.showOpenDialog(new GridBagPanel) match {
          case FileChooser.Result.Approve => text = chooser.selectedFile.getPath
          case FileChooser.Result.Cancel  => println("Canceled")
          case FileChooser.Result.Error   => println("UNKNOWN Error")
        }
    }

    listenTo(goBtn)
    reactions += {
      case ButtonClicked(button) if (button == goBtn) =>
        try {
          SsConverter.go(text)
          Dialog.showMessage(button, "完了しました。")
        } catch {
          case e:FileNotFoundException if e.getMessage.matches(".*Permission denied.*") =>
            Dialog.showMessage(button,"ファイルへの書き込み権限がありません\n" + e.getMessage)
          case e:FileNotFoundException if e.getMessage.matches(".*No such file or directory.*") =>
            Dialog.showMessage(button,"ファイルが見つかりません\n" + e.getMessage)
          case e =>
            val st = e.getStackTrace
            Dialog.showMessage(button, e.getMessage)
            throw(e)
        }
      }
  }

  // ----------------------------------------------------
  val DefaultFile = "input/input.xls"

  // ----------------------------------------------------
  def top = new MainFrame {
    title = "SsConverter v1.0"
    minimumSize = new java.awt.Dimension(400, 100)

    contents = new BoxPanel(Orientation.Vertical) {
      contents.append(new FlowPanel{ contents.append(textfield, fileSelectBtn)})
      contents.append(new BorderPanel{add(goBtn, BorderPanel.Position.Center) })
      
      border = Swing.EmptyBorder(5, 5, 5, 5)
    }
  }
}

このようになった。

と、ここでふとNetBean6.1をつかってGUIのデザインを出来ないかと考えてみた。
で、やってみたら・・・

import java.io._
import swing._
import swing.event._
import javax.swing._

object SsConverterGUI2 extends SimpleGUIApplication {
  // ----------------------------------------------------
  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName)
  val chooser = new FileChooser(new File("."))

  // ----------------------------------------------------
  object fileSelectBtn extends Button { text = "ファイル選択" }
  object goBtn extends Button { text = "実行" }

  // ----------------------------------------------------
  object textfield extends TextField {
    columns = 30
    text = DefaultFile
    
    listenTo(fileSelectBtn)
    reactions += {
      case ButtonClicked(button) if (button == fileSelectBtn) =>
        chooser.showOpenDialog(new GridBagPanel) match {
          case FileChooser.Result.Approve => text = chooser.selectedFile.getPath
          case FileChooser.Result.Cancel  => println("Canceled")
          case FileChooser.Result.Error   => println("UNKNOWN Error")
        }
    }

    listenTo(goBtn)
    reactions += {
      case ButtonClicked(button) if (button == goBtn) =>
        try {
          SsConverter.go(text)
          Dialog.showMessage(button, "完了しました。")
        } catch {
          case e:FileNotFoundException if e.getMessage.matches(".*Permission denied.*") =>
            Dialog.showMessage(button,"ファイルへの書き込み権限がありません\n" + e.getMessage)
          case e:FileNotFoundException if e.getMessage.matches(".*No such file or directory.*") =>
            Dialog.showMessage(button,"ファイルが見つかりません\n" + e.getMessage)
          case e =>
            val st = e.getStackTrace
            Dialog.showMessage(button, e.getMessage)
            throw(e)
        }
      }
  }

  // ----------------------------------------------------
  val DefaultFile = "input/input.xls"
  
  // ----------------------------------------------------
  def top = new MainFrame {
    title = "SsConverter v1.0b"
    minimumSize = new java.awt.Dimension(400, 100)

    //-----------------------------------------------------
    // Map Objects
    val jTextField1 = textfield.peer
    val jButton1 = fileSelectBtn.peer
    val jButton2 = goBtn.peer

    //-----------------------------------------------------
    // Initialize
    import java.lang.Short
    val layout = new GroupLayout(peer.getContentPane);
    peer.getContentPane.setLayout(layout);

    //-----------------------------------------------------
    // Paste Generated Code
    //
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addGroup(layout.createSequentialGroup()
            .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE))
          .addComponent(jButton2, javax.swing.GroupLayout.DEFAULT_SIZE, 413, Short.MAX_VALUE))
        .addContainerGap())
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
          .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
          .addComponent(jButton1))
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(jButton2)
        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );
    
    //-----------------------------------------------------
    pack();
  }
}

と、こんな感じになった。

  • 前半部分は一切手を入れなくて大丈夫だった、
  • peerをつかって、Javaのオブジェクトを取り出すのがポイント

やっぱりScalaJavaは相性がいい。(^^
こっちのほうは、リサイズしたときの挙動が美しくてうれしい。(^o^

しかも

  • Paste Generated Codeの部分はNetBeanの生成したコードそのままなので修正があっても楽!

ただ、NetBean上のGUIエディタで現在のウィンドウのたてのサイズがうまく取得できなかった(というか取得の方法がわからなかった)ので、最小サイズは目分量なのが心残り・・・