JavaFX TreeView with Drag&Drop functionality produces an exception

时间:2018-04-20 21:29:07

标签: javafx treeview

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();
    }
}

1 个答案:

答案 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;
}