在 ScalaFX 中,如果我将 TreeCell 拖放到包含 TreeView 之外的控件上,则会播放一个简短的动画,显示拖动的项目返回到其原始位置。
如果我将 TreeCell 放到应用程序之外,也会发生同样的情况 - 例如放到桌面上。
如果我将 TreeCell 放到不应被接受的位置的包含 TreeView 上,我希望播放相同的动画,但设置:
event.dropCompleted = false
不足以产生这种效果。
有没有办法从 TreeCell 的 onDragDropped 事件处理程序中播放放置失败的动画?
编辑
根据要求添加了代码示例。将一个条目拖放到控件外,您将看到放置失败的动画。将一个条目拖放到列表下方,动画不会播放。问题是如何让动画在第二种情况下播放。
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"))
}
}
}
}