ScalaFXでTreeView
ScalaFXはJavaFX 2.2.xのラッパーでScala言語で書かれたUI DSLです。
JavaFX 2.2.xのラッパーとしては開発が進んでいる方です。
最近ScalaFX 1.0 M5とScalaFX 8.0 M1が出ました。
今回はIDEにIntelliJ IDEA 12 Community Editionを使いScalaFX 1.0 M5でTreeViewを作成します。
Scalaはすでにホームディレクトリにインストールしてあるscala-2.10.1を使います。
Pluginのインストールはこのサイトが親切丁寧です。
【図解】Scala 2.10 + IntelliJ IDEA 12 で「Hello World」する
すでにscala-2.10.1がインストールしてある場合など若干の変更をすれば良いです。
準備ができていると仮定します。
1. FileメニューよりNew Project...を選択。
プロジェクト名、Scala Homeを記入
2. Fileメニューから”Project Structure...”を選択
Project Settingsの中のLibrariesを選択
3. "+" をクリック
4. scalafx_2.10-1.0.0-M5.jarを追加する。
5. srcフォルダをcontrolキー+クリック又はマウスの右クリックでNew=>Scala Classを作成します。
TreeViewSampleの元のコードはオラクルのJavaFXチュートリアルにあるものを使いこれをScalaFXで書き直しました。
13 Tree View
ScalaFXのTreeViewは開発途中ということもあってラップが中途半端な感じです。
このためコンパイル実行が可能なようにコードを少し工夫してあります。
TreeViewSample.scala
/** * Created with Intellij IDEA. * User: hshino * Date: 13/09/14 * Time: 20:32 * To change this template use File | Settings | File Templates. */ import scalafx.Includes._ import scalafx.application.JFXApp import scalafx.application.JFXApp.PrimaryStage import scalafx.scene.Node import scalafx.scene.Scene import scalafx.scene.control.TextField import java.util import scalafx.scene.control.TreeItem import scalafx.scene.control.TreeView import scalafx.scene.image.Image import scalafx.scene.image.ImageView import scalafx.scene.input.KeyEvent import javafx.scene.{control => jfxsc} import scalafx.scene.paint.Color import javafx.util.Callback import javafx.scene.{input => jfxsi} import scalafx.beans.property.StringProperty import scalafx.scene.layout.VBox import scalafx.scene.layout.Priority class Employee (name: String , department: String ){ val name2:StringProperty = new StringProperty(name) val department2:StringProperty = new StringProperty(department) def getName:String = { name2.get() } def setName(fName:String ):Unit = { name2.set(fName) } def getDepartment:String = { department2.get() } def setDepartment(fName:String ):Unit = { department2.set(fName) } } class TextFieldTreeCellImpl extends jfxsc.TreeCell[String] { private val tfDelegate: jfxsc.TextField = new jfxsc.TextField private var tf: TextField = _ override def startEdit(){ super.startEdit() if (tf == null) { createTextField() } setText(null) setGraphic(tf) tf.selectAll() } override def cancelEdit(){ super.cancelEdit() setText(getItem) setGraphic(getTreeItem.getGraphic) } override def updateItem(item:String , empty: Boolean ) { super.updateItem(item, empty) if (empty) { setText(null) setGraphic(null) } else { if (isEditing) { if (tf != null) { tf.setText(getString) } setText(null) setGraphic(tf) } else { setText(getString) setGraphic(getTreeItem.getGraphic) } } } def createTextField():Unit = { tf = new TextField(tfDelegate) println("tf:TextField = " + tf) tf.setText (getString) tf.setEditable(true) tf.onKeyReleased = (event: KeyEvent) => { if (event.getCode == jfxsi.KeyCode.ENTER) { println("KeyCode.ENTER") commitEdit(tf.getText) } else if (event.getCode == jfxsi.KeyCode.ESCAPE) { cancelEdit() } } } def getString: String ={ if(getItem == null ){ "" }else{ getItem.toString } } } object TreeViewSample extends JFXApp { private val tvDelegate: jfxsc.TreeView[String] = new jfxsc.TreeView[String] private var tv: TreeView[String] = _ val rootIcon: Node = { new ImageView(new Image(this.getClass.getClassLoader.getResourceAsStream("root.png"))) } private val rootNodeDelegate: jfxsc.TreeItem[String] = new jfxsc.TreeItem[String] private var rootNode: TreeItem[String] = _ rootNode = new TreeItem[String](rootNodeDelegate) val depIcon = { new Image(this.getClass.getClassLoader.getResourceAsStream("department.png")) } val employees = util.Arrays.asList( new Employee("Ethan Williams", "Sales Department"), new Employee("Emma Jones", "Sales Department"), new Employee("Michael Brown", "Sales Department"), new Employee("Anna Black", "Sales Department"), new Employee("Rodger York", "Sales Department"), new Employee("Susan Collins", "Sales Department"), new Employee("Mike Graham", "IT Support"), new Employee("Judy Mayer", "IT Support"), new Employee("Gregory Smith", "IT Support"), new Employee("Jacob Smith", "Accounts Department"), new Employee("Isabella Johnson", "Accounts Department")) for (i <- 0 to employees.size -1) { val empLeaf:TreeItem[String] = new TreeItem[String](employees.get(i).getName) var found:Boolean = false for ( depNode <- rootNode.getChildren) { if (depNode.getValue.contentEquals(employees.get(i).getDepartment)){ depNode.getChildren.add(empLeaf) found = true } } if (!found) { val depNode:TreeItem[String] = new TreeItem[String]( employees.get(i).getDepartment, new ImageView(depIcon) ) rootNode.getChildren.add(depNode) depNode.getChildren.add(empLeaf) } } stage = new PrimaryStage { title = "Tree View Sample" width = 500 height = 500 println("rootNode = " + rootNode) rootNode.value = "MyCompany Human Resources" rootNode.graphic = rootIcon rootNode.setExpanded(true) tv = new TreeView(tvDelegate) tv.setRoot(rootNode) tv.setShowRoot(true) tv.setEditable(true) tv.setPrefSize(500, 500) tv.vgrow = Priority.ALWAYS tv.hgrow = Priority.ALWAYS tv.setCellFactory(new Callback[jfxsc.TreeView[String],jfxsc.TreeCell[String]](){ override def call( p: jfxsc.TreeView[String]) :jfxsc.TreeCell[String] = { new TextFieldTreeCellImpl() } }) scene = new Scene { fill = Color.LIGHTGRAY root = new VBox { vgrow = Priority.ALWAYS hgrow = Priority.ALWAYS content = tv } } } }
6. 後はdepartment.pngとroot.pngをsrcフォルダにコピーしてRunメニューからRunさせてください。
ProScalaFXには参考になるコードが沢山あります。