2

I want to set custom cursor during drag & drop events. I want to override cursor to e.g. classic open hand one.

    b.setOnDragDetected(e -> {
        Dragboard db = b.startDragAndDrop(TransferMode.MOVE);
        ClipboardContent content = new ClipboardContent();
        content.putString("");
        db.setContent(content);
        b.setCursor(Cursor.CLOSED_HAND);
    });

    b.setOnDragOver(e -> {
        if (e.getSource() != b)
            e.acceptTransferModes(TransferMode.MOVE);
        b.setCursor(Cursor.CLOSED_HAND);
    });

Unfortunately DragEvent.acceptTransferModes() is setting cursor to one of the move/link/copy and ignores my change. Is there a way to set any other cursor?

mtadmk
  • 63
  • 1
  • 7

2 Answers2

1

As you´re not posting a MVCE and we just can guess what the problem is i wrote a simple example which shows all kind of Drag&Drop event. I guess you are not reseting the Cursor to the default one?

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.ImageCursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


    public class MainApp extends Application {

        @Override
        public void start(Stage primaryStage) {

            Pane pane = new Pane();
            pane.setMinSize(400, 400);
            pane.setPadding(new Insets(10));

            Button b = new Button("Drag Source (b)");
            Button c = new Button("Drag Target (c)");
            //here we load a custom image
            Image img = new Image("http://2.bp.blogspot.com/-ipjep9g59YY/VbqLU1vD9qI/AAAAAAAAAOc/CjB4YvRYz_M/s1600/skype-drunk.jpg");

            b.setOnDragOver(event->{
                    if (event.getGestureSource() != b && event.getDragboard().hasString()) {
                        event.acceptTransferModes(TransferMode.MOVE);
                        System.out.println("DragOver (b)");
                    }
                    event.consume();
            });

            b.setOnDragDropped(e -> {
                System.out.println("DragDropped (b)");
                //added following line as cursor wasn´t reseted to default
                b.setCursor(Cursor.DEFAULT);
                e.setDropCompleted(true);
                e.consume();
            });

            b.setOnDragExited(event->{
                event.consume();
                System.out.println("DragExited (b)");
            });

            b.setOnDragDetected(e-> {
                Dragboard db = b.startDragAndDrop(TransferMode.MOVE);

                ClipboardContent content = new ClipboardContent();
                content.putString("Hey i´m b");
                db.setContent(content);
                //b.setCursor(Cursor.OPEN_HAND);
                b.setCursor(new ImageCursor(img));
                e.consume();
            });

            b.setOnDragDone(event->{
            /* the drag and drop gesture ended */
            /* if the data was successfully moved, do something and reset Cursor */
                    if (event.getTransferMode() == TransferMode.MOVE) {                        
                        //b.setCursor(Cursor.DEFAULT);
                    }
                    b.setCursor(Cursor.DEFAULT);
                    event.consume();
            });

            c.setOnDragOver(event->{
                if (event.getGestureSource() != c && event.getDragboard().hasString()) {
                    event.acceptTransferModes(TransferMode.MOVE);
                    System.out.println("DragOver (c)");
                }

                event.consume();

            });

            c.setOnDragDropped(e -> {
                System.out.println("DragDropped (c)");
                e.setDropCompleted(true);
                e.consume();
            });

            c.setOnDragExited(event->{
                event.consume();
                System.out.println("DragExited (c)");
            });


            c.setOnDragDetected(e-> {
                Dragboard db = c.startDragAndDrop(TransferMode.MOVE);

                ClipboardContent content = new ClipboardContent();
                content.putString("Hey i´m c");
                db.setContent(content);
                c.setCursor(Cursor.OPEN_HAND);
                e.consume();
            });
            c.setOnDragDone(event->{
            /* the drag and drop gesture ended */
            /* if the data was successfully moved, do something and reset Cursor */
                if (event.getTransferMode() == TransferMode.MOVE) {
                    c.setCursor(Cursor.DEFAULT);
                }
                event.consume();
            });

            VBox box = new VBox(b,c);
            box.setSpacing(20);

            BorderPane root = new BorderPane(pane, box, null, null, null);
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();
        }


        public static void main(String[] args) {
            launch(args);
        }
    }
Inge
  • 427
  • 7
  • 20
  • Well this is exactly what is not working. When you are setting cursor in onDragDetected to OPEN_HAND it is being changed automatically during drag over to http://imgur.com/5vnDr8U or http://imgur.com/kWZQgcU. My intention however is to set some custom cursors instead of these two. – mtadmk Feb 18 '16 at 08:22
  • But then my previous answer was what you were looking for `Image image = new Image("myCustomCursorImage.png"); b.setCursor(new ImageCursor(image)); ` or maybe i just don't understand where the problem is. As RAndrs00 mentioned a MVCE is always a good way... – Inge Feb 18 '16 at 08:47
  • Your MVCE is perfect. Maybe I wasn't precise enough - I want to set any different cursor than standard one. Either custom from image or any defined in Cursor class. Maybe gif would show it http://imgur.com/rr9Gk8R. In your code there is OPEN_HAND set during drag detection. Unfortunately it is overridden by cursors from my first comment. I want to change them but I am unable to to this. – mtadmk Feb 18 '16 at 09:28
  • I changed the code to reflect a custom cursor hope that helps – Inge Feb 19 '16 at 07:19
0

You may not need to use DragBoard at all, instead just save the dragged item in to member var then receive it from there. Following code works well, just don't use dragBoard.startDragAndDrop() function with that TransferMode. Instead code that functionality, that is how i prevent the Java DragBoard to set that ugly System-Cursor! I know if you drag data (String,Html,File) from the OS-System over the scene it will use the nicier OS drag cursor labels with some system texts like "copy file" or "link" but if you just need to drag some internal java objects the use of that DragBoard isn't neccesary, it would show these ugly empty cursor labels anyway. The method setOnDragOver() doesn't responds if dragBoard.startDragAndDrop() wasn't called before, but instead you can take use of the "start full drag" method row.startFullDrag(), then the setOnMouseDragXX() (XX:Entered,Exited,Released) methods are available to use. Beside, the DragBoard class is final, there is no way to overwrite the responsible method implementations. Here is some example code that works in my case i use it to sort table rows manually, just recode it and adapt it to your needs:

    private ToggleTableRowCell<AbstractNodeItem> selRow = null;
    private ToggleTableRowCell<AbstractNodeItem> styledRow = null;
    private ToggleTableRowCell<AbstractNodeItem> dropRow = null;

    private static final String DROP_DOWN_TABLEROW_HINT_STYLE = "-fx-border-width:1; -fx-border-color: transparent color-cell-border color-dragged color-cell-border;";
    private static final String DROP_UP_TABLEROW_HINT_STYLE = "-fx-border-width:1; -fx-border-color: color-dragged color-cell-border color-cell-border color-cell-border;";
    private static final String DROP_FORBIDDEN_TABLEROW_HINT_STYLE = "-fx-border-width:1; -fx-border-color: red;";

    Image cursorForbidden = new Image("/resources/images/YourCursor.png");
    // make own cursor
    Cursor forbiddenCursor = new ImageCursor(cursorForbidden, cursorForbidden.getWidth() / 2,
            cursorForbidden.getHeight() / 2);

    ImageView rowSnapshot = new ImageView();

    /* TableRowFactory with Drag & Drop Sorting */
    tableView.setRowFactory(table -> {
        ToggleTableRowCell<AbstractNodeItem> row = new ToggleTableRowCell<>();

        /* adding manual sorting functionality */
        row.setOnDragDetected(event -> {
            if (row.isEmpty()) { return; }
            this.selRow = row;

            Integer itemIndex = row.getItem().getID();

            // Get snapshot of the row
            SnapshotParameters snapshotParams = new SnapshotParameters();
            snapshotParams.setFill(Color.TRANSPARENT);
            WritableImage snapshot = row.snapshot(snapshotParams, null);
            rowSnapshot.setImage(snapshot);

            // Start full drag
            row.startFullDrag();

            ClipboardContent cc = new ClipboardContent();
            cc.put(SERIALIZED_MIME_TYPE, itemIndex);

            final String data = row.getItem().getData();
            cc.putString(data);
            event.consume();
        });

        row.setOnMouseDragEntered(event -> {
            if (SortOrder.ID.isNotCurrent()) { return; }
            // remove old CSS-Hint
            if (null != this.styledRow) {
                this.styledRow.setStyle("");
            }

            if (!row.isEmpty() && row != this.selRow) {
                this.dropRow = row;
            }

            this.styledRow = row;

            int selRowIndex = this.selRow.getIndex();

            // can't drop on itself
            if (row.getIndex() == selRowIndex) {
                this.styledRow.setStyle(DROP_FORBIDDEN_TABLEROW_HINT_STYLE);
                tableView.setCursor(forbiddenCursor);

            } else {
                if (row.isEmpty()) {
                    if (selRowIndex == tableView.getItems().size() - 1) {
                        this.styledRow = this.selRow;
                        this.styledRow.setStyle(DROP_FORBIDDEN_TABLEROW_HINT_STYLE);
                        this.dropRow = null;
                        tableView.setCursor(forbiddenCursor);
                    } else {
                        this.styledRow = this.dropRow;
                        this.styledRow.setStyle(DROP_DOWN_TABLEROW_HINT_STYLE);
                        tableView.setCursor(Cursor.HAND);
                    }

                } else {

                    if (selRowIndex > row.getIndex())
                        this.styledRow.setStyle(DROP_UP_TABLEROW_HINT_STYLE);
                    else {
                        this.styledRow.setStyle(DROP_DOWN_TABLEROW_HINT_STYLE);
                    }
                    tableView.setCursor(Cursor.HAND);
                }
            }
        });
        return row;
    });

    tableView.setOnMouseDragExited(e -> {
        if (null != styledRow) {
            styledRow.setStyle("");
        }
        tableView.setCursor(Cursor.DEFAULT);
    });

    tableView.setOnMouseDragReleased(event -> {
        // remove old CSS-Hint
        if (null != styledRow) {
            styledRow.setStyle("");
        }

        tableView.setCursor(Cursor.DEFAULT);

        if (!SortOrder.ID.isCurrent()) { return; }

        /* clear CSS-Hint-Style */
        if (null != styledRow) {
            styledRow.setStyle("");
        }

        if (null == dropRow) { return; }
    
        int dropIndex = dropRow.getIndex();
        int selRowIndex = selRow.getIndex();

        // don't drop on itself or empty cells
        if (dropRow.getIndex() != selRowIndex) {
            // cut and move the cell here
        }
    });