続Scala2.8でSwing

はまったり理解したりした事。突っ込み歓迎。
作業環境はNetBeans6.9.1です。

ScalaでSwingをする上で、SimpleSwingApplication初め、便利なラッパークラスがあるのはわかったけど、ラッパークラスにメソッドがなかった場合にはどうするのか?
多分peerを使います。

以下、具体例。

import scala.swing._
import scala.swing.event._
import scala.swing.Swing._

object Main extends SimpleSwingApplication {
  def top = new MainFrame {
    contents = new BorderPanel{
      .............
    }
    menuBar = new MenuBar{
      contents += new Menu("ヘルプ"){
        contents += new MenuItem("ヘルプ")
        peer.addSeparator                       //<- ここで使ってる。
        contents += new MenuItem("このアプリについて")
      }
    }
  }
}

上の例はJavaでいえば、JMenuBarのメニューにぶら下がってる?メニューアイテム間に区切り線(JSeparator)をいれてるんですが、JMenuのラッパークラスである、MenuにはaddSeparator()に相当するメソッドがありません(多分)。
ちなみにJSeparatorをラップしたSeparatorクラスはあります。
こんな時に上のようにpeerを使ってJavaのメソッドを呼び出す事ができます。
上の例ではaddSeparator()を呼んでいます。
このpeerというのはlazy valになっていて、各ラッパークラスに定義されています。
中身はというとラップ対象のJavaクラスです。
なので上記の場合はMenuなので返ってくるのはJMenuという事になります。
非常に短いので実際の定義をみてみます。こんな感じです。

 override lazy val peer: JMenu = new JMenu(title0)

というわけで、メソッドないぞーという場合にはpeerを使って呼び出すといいと思います。
ただ、当たり前ですが、もし、引数や返り値があるメソッドを呼び出す場合、引数や返り値は当然scalaのラッパークラスでないので注意が必要です*1
蛇足ですが、コード見ると、内部的に結構つかわれてますね。
ラップ対象をどっかでは呼ばなきゃいけないから当然といえば当然でしょうか?
ラッパーのメソッドの中でpeer.getVerticalScrollBarとか。


次はBorderPanelやScrollPane等について。
BorderPanelとは何かというと、ボーダーレイアウトのJPanelのラッパーのようです。
ScrollPaneはJScrollPaneのラッパーですね。
で、当然、パネルに部品を配置したりとか、スクロールバーの表示ポリシーなんかをセットしようとするわけです。

//Javaだとこんな感じの
...
jScrollPaneInstance.setHorizontalScrollBarPolicy(javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
.....
hoge.add(jLabel,BorderLayout.CENTER);
......

これをScalaでやろうとして、apiを引いてみて一瞬むむっとなりました。
例えばsetHorizontanScrollBarに相当するセッターメソッドを見てみると・・

def horizontalScrollBarPolicy_=(p: Value): Unit

Valueってなんぞという*2
で、よくわからないのでソースコードを見て調べたのですが、実際に書くとコードとしては下記のようになります。

....
    val scrollPane = new ScrollPane{
      viewportView = new TextArea
      import ScrollPane.BarPolicy._
      this.horizontalScrollBarPolicy = AsNeeded
    }
    contents = new BorderPanel {
      import BorderPanel.Position._
      add(scrollPane, Center)
    }
...

ScrollPaneもBorderPanelもコンパニオンクラスになってます。というか大概のがコンパニオンクラスになっているのかな?
で、コンパニオンクラスのオブジェクト側がEnumerationをextendsしたオブジェクトを内部に持っています*3
この内部オブジェクトがボーダーレイアウトのPositionやスクロールバーのポリシーなどを定義しています。
なので、これらを呼んであげればOKとなります。
例ではそれぞれ一カ所ずつなので、わざわざインポートするまでもない気がしますが・・。
ここらへん、NetBeansの補完は例えばimport文を入力した後でないとCenterとか出てくれなかったりと、補完機能はまだまだなので、現状はソースコードやドキュメントに当たるしかない感じです。
APIも内部オブジェクトのは表示してくれないので。
間違ってました。メソッドの引数をクリックした先の所から直接たどれば一応見ることができました。今回の場合はクリックするとValueのapi→BarPolicyのリンクをクリックです。左の一覧には出てないんですよね。分かりづらい・・・。



ScalaでSwingやる場合のドキュメントとかサンプルですが、公式のPDFコップ本ぐらいしかない気がします。
後はScala勉強会@東北のみんなのコードとか。
公式のPDFは17ページしかありませんので、目を通しておくと吉です。


JavaのSwingの勉強もしながらという感じになっているので結構時間がかかっている感じ。むーん。

*1:引数や返り値があるのは全部ラップされているのだろうか?確認していない

*2:後で気づいたけど、Valueの所にカーソルもってったら、hoverでscala.swing.ScrollPane. BarPolicy.Valueって出てましたorz.クリックしたら飛び先でclass Value extends Valとか出てるのはわかりづらいと思いました。

*3:ちなみにScalaの列挙は標準クラスのEnumerationを拡張するオブジェクトを定義します