ScalaFX では、含まれている TreeView 以外のコントロールに TreeCell をドロップすると、ドラッグされたアイテムが元の位置に戻る短いアニメーションが再生されます。
TreeCell をアプリケーションの外 (デスクトップなど) にドロップすると、同じことが起こります。
TreeCell を含む TreeView の受け入れられない場所にドロップすると、同じアニメーションを再生したいのですが、次のように設定します。
event.dropCompleted = false
この効果を生み出すには十分ではありません。
TreeCell の onDragDropped イベント ハンドラ内からドロップ失敗アニメーションを再生する方法はありますか?
編集
リクエストに応じてコード サンプルを追加しました。エントリをドラッグしてコントロールの外にドロップすると、ドロップ失敗のアニメーションが表示されます。エントリをリストの下にドラッグ アンド ドロップすると、アニメーションが再生されません。問題は、2 番目のケースでアニメーションを再生する方法です。
import scalafx.application.JFXApp
import scalafx.scene.Scene
import scalafx.scene.paint.Color
import scalafx.scene.layout.Pane
import scalafx.Includes._
import scalafx.scene.input.{TransferMode, DataFormat, DragEvent, MouseEvent}
import scalafx.scene.control._
import javafx.scene.control.{TreeItem => jfxTreeItem}
import java.nio.ByteBuffer
import java.util
import scalafx.beans.value.ObservableValue
class StringRootItem(text: String) extends TreeItem[String](text) {
override def toString() = text
}
class StringTreeItem(text: String) extends TreeItem[String](text) {
override def toString() = text
}
object DragAndDropControl {
def apply(rootNodeName: String, entries: List[String]): DragAndDropControl = {
val rootItem = new StringRootItem(rootNodeName)
rootItem.setExpanded(true)
val children = rootItem.getChildren
entries.foreach(entry => {
children.add(new StringTreeItem(entry))
})
new DragAndDropControl(rootItem)
}
}
class DragAndDropControl(rootItem: StringRootItem) extends TreeView[String](rootItem) {
showRoot = false
cellFactory = (tree: TreeView[String]) => {
new StringDragAndDropCell(tree)
}
object StringDragAndDropCell {
val customFormat: DataFormat = new DataFormat("string.entry.custom")
var transferItem: TreeItem[String] = null
def toBuffer(entry: String): ByteBuffer = ByteBuffer.allocate(10)
def fromBuffer(buffer: ByteBuffer): String = null
}
class StringDragAndDropCell(tree: TreeView[String]) extends TreeCell[String] {
import StringDragAndDropCell._
private var stringEntry: String = null
onDragDetected = (event: MouseEvent) => {
val db = startDragAndDrop(TransferMode.MOVE)
import scala.collection.JavaConversions._
if ((treeItem ne null) && (treeItem.value ne null) && (treeItem.value.getValue ne null)) {
transferItem = treeItem.value
val content: Map[javafx.scene.input.DataFormat, AnyRef] = Map(customFormat.delegate -> toBuffer(transferItem.value()))
val contentMap: util.Map[javafx.scene.input.DataFormat, AnyRef] = mapAsJavaMap(content)
db.setContent(contentMap)
}
event.consume()
}
onDragOver = (event: DragEvent) => {
val db = event.getDragboard
if (db.hasContent(customFormat))
event.acceptTransferModes(TransferMode.MOVE)
event.consume()
}
onDragDone = (event: DragEvent) => {
if (event.transferMode == TransferMode.MOVE)
event.dragboard.clear()
event.consume()
}
onDragDropped = (event: DragEvent) => {
val db = event.getDragboard
var success = false
if (db.hasContent(customFormat))
success = stringEntry ne null
if (success)
if (event.gestureSource != event.delegate.getGestureTarget) {
treeItem().getParent.getChildren.removeAll(transferItem)
treeItem().getParent.getChildren.add(index(), transferItem)
}
event.dropCompleted = success
event.consume()
}
/*
* Change handler for the treeItem property.
*
* The treeItem property is set by JavaFX after construction and at any time when the cell is recycled for UI virtualization.
*
* The text property must be updated when the treeItem is set in order for the cell to render correctly (without this the cell will appear blank.)
*/
super.treeItem.onChange((observable: ObservableValue[jfxTreeItem[String], jfxTreeItem[String]], oldValue: jfxTreeItem[String], newValue: jfxTreeItem[String]) => {
if (newValue ne null) {
stringEntry = newValue.getValue
text = stringEntry
}
else
stringEntry = null
})
override def toString(): String = {
if (stringEntry == null)
null
else
s"ScalaFX string tree cell ${stringEntry.toString}"
}
}
}
object TestDragAndDrop extends JFXApp
{
println("javafx.runtime.version: " + System.getProperties.get("javafx.runtime.version"))
println("java.runtime.version: " + System.getProperties.get("java.runtime.version"))
stage = new JFXApp.PrimaryStage {
title = "Test Drag and Drop"
width = 600
height = 472
scene = new Scene {
fill = Color.LIGHTGREEN
root = new Pane {
content = DragAndDropControl("Numbers", List("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"))
}
}
}
}