I'm new to JavaFX. I would like to implement a JavaFX TreeView
with Drag&Drop functionality.
I do the following: I create a TreeView
instance (treeView
) and a root node of type ProgramRootTreeItem
(this class extends TreeItem
).
To the root node I add some child node of type ProgramTreeItem
(this also extends TreeItem
).
After this I add the root node to treeView and register a cellFactory
(DnDTreeCell
) to it.
DnDTreeCell
implements all the event handling regarding to Drag&Drop.
I can compile, but if I execute I get an exception:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to pluginmanagement.ProgramTreeItem
at pluginmanagement.DnDTreeCell.updateItem(DnDTreeCell.java:15)
I have absolutely no idea, why I get this exception. Can you help me please? Thanx in advance.
DnDTreeApp.java
package pluginmanagement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeItem.TreeModificationEvent;
import javafx.scene.control.TreeView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class DnDTreeApp extends Application {
public static void main(String[] args) {
Application.launch(DnDTreeApp.class, args);
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Example Dynamic Tree");
primaryStage.setResizable(true);
final VBox box = new VBox();
box.setFillWidth(false);
Scene scene = new Scene(box);
primaryStage.setScene(scene);
box.getChildren().add(this.getExampleTree());
primaryStage.show();
}
private TreeView<ProgramTreeItem> getExampleTree() {
TreeView<ProgramTreeItem> treeView = new TreeView<ProgramTreeItem>();
ProgramRootTreeItem root = buildTree();
treeView.setCellFactory(new Callback<TreeView<ProgramTreeItem>, TreeCell<ProgramTreeItem>>() {
@Override
public TreeCell call(TreeView<ProgramTreeItem> param) {
System.out.format("\ncall() - param: %s\n", param);
TreeCell cell = new DnDTreeCell(param);
System.out.format("\ncall() - return: %s\n", cell);
return cell;
}
});
treeView.setPrefSize(1000, 750);
treeView.setShowRoot(true);
treeView.setRoot(root);
root.setExpanded(true);
return treeView;
}
private ProgramRootTreeItem buildTree() {
ProgramRootTreeItem root = new ProgramRootTreeItem();
for(int a=1; a<4; a++) {
for(int b=1; b<4; b++) {
ProgramTreeItem child = new ProgramTreeItem("child_" + a + "_" + b);
root.getChildren().add(child);
}
}
return root;
}
}
DnDTreeCell.java
package pluginmanagement;
import javafx.event.EventHandler;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DataFormat;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
public class DnDTreeCell extends TreeCell<ProgramTreeItem> {
private TreeView<ProgramTreeItem> parentTree;
private ProgramTreeItem item;
public DnDTreeCell(final TreeView<ProgramTreeItem> parentTree) {
System.out.format("\nCTR - DnDTreeCell: [%s]\n", parentTree);
this.parentTree = parentTree;
// ON SOURCE NODE.
setOnDragDetected(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
System.out.println("\nDrag detected on " + item);
if (item == null) {
return;
}
Dragboard dragBoard = startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
content.put(DataFormat.PLAIN_TEXT, item.toString());
dragBoard.setContent(content);
event.consume();
}
});
setOnDragDone(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println("\nDrag done on " + item);
dragEvent.consume();
}
});
// ON TARGET NODE.
// setOnDragEntered(new EventHandler<DragEvent>() {
// @Override
// public void handle(DragEvent dragEvent) {
// System.out.println("Drag entered on " + item);
// dragEvent.consume();
// }
// });
setOnDragOver(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
System.out.println("\nDrag over on " + item);
if (dragEvent.getDragboard().hasString()) {
String valueToMove = dragEvent.getDragboard().getString();
if (!valueToMove.matches(item.toString())) {
// We accept the transfer!!!!!
dragEvent.acceptTransferModes(TransferMode.MOVE);
}
}
dragEvent.consume();
}
});
// setOnDragExited(new EventHandler<DragEvent>() {
// @Override
// public void handle(DragEvent dragEvent) {
// System.out.println("Drag exited on " + item);
// dragEvent.consume();
// }
// });
setOnDragDropped(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent dragEvent) {
String valueToMove = dragEvent.getDragboard().getString();
ProgramTreeItem itemToMove = search((ProgramTreeItem) parentTree.getRoot(), valueToMove);
ProgramTreeItem newParent = search((ProgramTreeItem) parentTree.getRoot(), item.toString());
if (!newParent.getParent().equals(itemToMove)) {
// Remove from former parent.
System.out.format("\nDrag dropped on " + item + "; ItemToMove: %s; NewParent: %s\n", itemToMove, newParent);
itemToMove.getParent().getChildren().remove(itemToMove);
// Add to new parent.
newParent.getChildren().add(itemToMove);
newParent.setExpanded(true);
} else {
System.out.format("\nDrop not Allowed !\n");
}
dragEvent.consume();
}
});
}
private ProgramTreeItem search(final ProgramTreeItem currentNode, final String valueToSearch) {
ProgramTreeItem result = null;
if (currentNode.toString().matches(valueToSearch)) {
result = currentNode;
} else if (!currentNode.isLeaf()) {
for (Object ch : currentNode.getChildren()) {
result = search((ProgramTreeItem)ch, valueToSearch);
if (result != null) {
break;
}
}
}
return result;
}
@Override
protected void updateItem(ProgramTreeItem item, boolean empty) {
System.out.format("\nupdateItem - [%s]\n", item);
super.updateItem(item, empty);
this.item = item;
String text = (item == null) ? null : item.toString();
setText(text);
}
}
ProgramRootTreeItem.java
package pluginmanagement;
public class ProgramRootTreeItem extends ProgramTreeItem {
public ProgramRootTreeItem() {
super("ROOT");
}
@Override
public boolean isRoot() {
return true;
}
@Override
public String toString() {
return "ProgramRootTreeItem_"+getUserObject();
}
}
ProgramTreeItem.java
package pluginmanagement;
import javafx.scene.control.TreeItem;
public class ProgramTreeItem extends TreeItem {
String userObj;
public ProgramTreeItem(String data) {
super(data);
userObj = data;
}
public String getUserObject() {
return userObj;
}
public boolean isRoot() {
return false;
}
@Override
public String toString() {
return "ProgramTreeItem_" + getUserObject();
}
}
答案 0 :(得分:1)
您错误地使用了TreeView
。
您被允许致电
的唯一原因treeView.setRoot(root);
是您的自定义TreeItem
实现扩展原始类型而不是指定类型参数。否则编译器会抱怨方法调用。
TreeItem
仅定义树的结构。传递给单元格的实际值存储在value
的{{1}}属性中。您的所有自定义TreeItem
商店TreeItem
。
当String
稍后尝试使用TreeView
中的值填充其单元格时,它会从TreeItem
获取String
但无法调用TreeItem
将这些值作为第一个参数,因为updateItem
需要DnDTreeCell
。
实际上,您的自定义ProgramTreeItem
课程不包含传统TreeItem
无法轻易获得的信息:
TreeItem
我建议使用public static boolean isRoot(TreeItem<?> item) {
return item.getParent() == null;
}
s:
TreeItem<String>
private TreeView<String> getExampleTree() {
TreeView<String> treeView = new TreeView<>();
TreeItem<String> root = buildTree();
treeView.setCellFactory(new Callback<TreeView<String>, TreeCell<String>>() {
@Override
public TreeCell call(TreeView<String> param) {
System.out.format("\ncall() - param: %s\n", param);
TreeCell<String> cell = new DnDTreeCell();
System.out.format("\ncall() - return: %s\n", cell);
return cell;
}
});
treeView.setPrefSize(1000, 750);
treeView.setShowRoot(true);
treeView.setRoot(root);
root.setExpanded(true);
return treeView;
}
private TreeItem<String> buildTree() {
TreeItem<String> root = new TreeItem<>();
for(int a=1; a<4; a++) {
for(int b=1; b<4; b++) {
TreeItem<String> child = new TreeItem<>("child_" + a + "_" + b);
root.getChildren().add(child);
}
}
return root;
}