scala.swingパッケージ内のクラスを利用して、ウィンドウの表示、コンポーネントの配置、イベントの取得などの基本的なことをやってみる。
SimpleSwingApplicationを使うと簡単にWindowが作成できる。
import scala.swing.{ SimpleSwingApplication, MainFrame, Dimension }
object MainFrameSample extends SimpleSwingApplication {
def top = new MainFrame {
// Windowのタイトル
title = "Window Title"
// Windowのサイズ
minimumSize = new Dimension( 300, 200 )
}
}
これで空のWindowが表示される。
上の例で使用しているtitleやminimumSizeはMainFrameクラスが持つメソッド。
MainFrameクラスでは他にも以下のような指定ができる。
// カーソルの指定
cursor = new Cursor( Cursor.HAND_CURSOR )
// リサイズ不能
resizable = false
// アイコンの設定(リソースにアイコンファイルが置いてある場合の例)
iconImage = ImageIO.read( getClass().getResourceAsStream( "icon.bmp" ) )
// メニューバーの指定
menuBar = new MenuBar() { contents += new Menu( "menu1" ) }
Linuxだと日本語表示で文字化けすることが良くあるので、先にその対策をしておく。
日本語が化けないフォントのファイルをリソースの中に入れておいて、デフォルトのフォントに設定してしまえば確実に文字化けは防げるはず。
// Resourceの中に入れておいたフォントを読み込む
val baseFont = new FontUIResource( Font.createFont( Font.TRUETYPE_FONT,
getClass().getResourceAsStream( "TakaoMincho.ttf" ) ).deriveFont( 14.0f ) )
// 読み込んだフォントをUIManagerでデフォルトに設定
import scala.collection.JavaConversions._
for ( entry <- UIManager.getDefaults().entrySet() )
if ( entry.getKey().toString().endsWith( ".font" ) )
UIManager.put( entry.getKey(), baseFont )
上の例ではリソースの中に入れておいたTakaoMincho.ttfのファイルを読み込んで、サイズを14に指定し、デフォルトフォントの内容を上書きしている。
JavaのJPanelのラッパーであるPanelを利用してコンポーネントを配置してみる。
ScalaのPanelには、BorderPanel、BoxPanel、FlowPanel、GridPanel、GridBagPanelなどがいる。JavaのSwingにいるBorderLayoutとかBoxLayoutを思い出すような名前。
とりあえずBoxPanelを使ってみる。BoxPanelは水平方向か垂直方向のどちらか一方にコンポーネントを並べて配置するレイアウト。
object BoxPanelSample extends SimpleSwingApplication {
def top = new MainFrame {
title = "Window Title"
minimumSize = new Dimension( 300, 100 )
// コンテンツにPanelを設定
contents = new BoxPanel( Orientation.Vertical ) {
contents += new Label( "展覧会の絵" )
contents += new Label( "クープランの墓" )
contents += new Button( "亡き王女のためのパヴァーヌ" )
}
}
}
上記のコードでは、垂直(Vertical)方向にコンポーネントが並ぶよう指定した上で、ラベルを2つ、ボタンを1つ配置している。
このコードを実行すると、以下のようなWindowが表示される。
以下のように、Panel内で背景色やツールチップ、枠線などを指定することもできる。
// コンテンツにPanelを設定
contents = new BoxPanel( Orientation.Vertical ) {
// コンポーネントの配置
contents += new Label( "展覧会の絵" )
// 背景色
background = Color.CYAN
// ツールチップ
tooltip = "ツールチップ"
// ボーダー
border = new LineBorder(Color.WHITE, 3)
}
BorderPanel、FlowPanel、GridPanel、GridBagPanelについても軽く試してみる。
BorderPanelはコンポーネントの配置場所をNorth、South、East、West、Centerの5つの中から選べる。
new BorderPanel() {
add( new Label( "展覧会の絵" ), BorderPanel.Position.North )
add( new Label( "クープランの墓" ), BorderPanel.Position.East )
add( new Button( "亡き王女のためのパヴァーヌ" ), BorderPanel.Position.South )
}
val flowPanel = new FlowPanel() {
contents += new Label( "展覧会の絵" )
contents += new Label( "クープランの墓" )
contents += new Button( "亡き王女のためのパヴァーヌ" )
}
val gridPanel = new GridPanel( 3, 2 ) {
contents += new Label( "展覧会" )
contents += new Label( "の絵" )
contents += new Label( "クープラン" )
contents += new Label( "の墓" )
contents += new Button( "亡き王女の" )
contents += new Button( "ためのパヴァーヌ" )
}
new GridBagPanel() {
layout += new Label( "展覧会" ) -> ( 0, 0 )
layout += new Label( "の絵" ) -> ( 1, 0 )
layout += new Label( "クープラン" ) -> ( 0, 1 )
layout += new Label( "の墓" ) -> ( 1, 1 )
// 3段目のマスは横に2つ繋げる
val c = pair2Constraints( 0, 2 )
c.gridwidth = 2
layout += new Button( "亡き王女のためのパヴァーヌ" ) -> c
}
ボタンクリックのイベントを取得して、ダイアログボックスを表示するコードを書いてみる。
こうした処理はreactionsにイベントごとの挙動を記述することで実現できるようだ。
// クリックされるとダイアログが出るボタン
contents += new Button( "押してみろ" ) {
reactions += {
case e: ButtonClicked => Dialog.showMessage( message = "ボタン押された" )
}
}
このコードを実行すると、下記のようにダイアログが出現するボタンが表示される。
ラベルの場合はデフォルトではイベントの発生を受け取る設定がされていないので、listenToで明示的に監視することを宣言してあげる必要がある。(Buttonは親クラス内でButtonClickedをイベント登録してるのでlistenToが不要だった)
// イベントによってテキストが変わるラベル
contents += new Label( "ラベル" ) {
listenTo( mouse.clicks, mouse.moves )
reactions += {
case e: MousePressed => text = "MousePressed"
case e: MouseReleased => text = "MouseReleased"
case e: MouseEntered => text = "MouseEntered"
}
}
このコードを実行すると、MouseEnteredやMousePressedに反応して文字が変化するラベルが表示される。
この辺のイベントの書き方はすっきりしていてけっこう好き。
ここまでラベルとボタンしか使ってこなかったので、他のコンポーネントも少し触ってみる。
テキストフィールド、チェックボックス、ラジオボタンなどのUIは一通り揃っている。プログレスバーやスライダーもいる。
def top = new MainFrame {
contents = new BoxPanel( Orientation.Vertical ) {
// テキストフィールド
contents += new TextField( "テキスト" )
// パスワード
contents += new PasswordField( "password" )
// テキストエリア
contents += new TextArea( "テキストエリア" )
// チェックボックス
contents += new CheckBox( "チェックボックス" )
// ラジオボタン
val button1 = new RadioButton( "ラジオボタン1" )
val button2 = new RadioButton( "ラジオボタン2" )
val group = new ButtonGroup( button1, button2 )
contents += button1
contents += button2
// プログレスバー
val progressBar = new ProgressBar()
progressBar.value = 30
contents += progressBar
// スライダー
contents += new Slider()
}
}