Change cursor in JavaFx ListView during drag and drop

本小妞迷上赌 提交于 2019-12-11 09:15:52

问题


I have a listview where I made it possible to rearrange the elements via drag-and-drop and it works fine, however I want to replace the two default icons with my own custom ones. I have tried with i.e. setCursor(Cursor.HAND) setCursor(new ImageCursor(image)) on both the ListCell itself or its parents but nothing gets reflected during the drag, only after, which is not what I want. Anyone know how to go about this?

Edit1: This question has nothing to do with how to create a reorder-able listview. It is about how to change the default cursor during drag-and-drop of a listview item. It is not a duplicate of
How to create a reorder-able TableView in JavaFx since it also has the very same default cursor icons during drag-n-drop.

Edit2: Affects Windows and Linux OS:es according to my findings, not Mac OS X.

screenshot drag-n-drop not allowed icon

screenshot drag-n-drop allowed icon

package sample;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.WritableImage;
import javafx.scene.input.*;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception{

        Pane pane = new Pane();
        ObservableList<String> items = FXCollections.observableArrayList("test1", "test2", "test3", "test4");
        ListView<String> lw = new ListView<>();
        lw.setCellFactory(param -> new MyListCell());
        lw.setItems(items);
        pane.getChildren().add(lw);
        stage.setTitle("RearrangeListView");
        stage.setScene(new Scene(pane, 300, 150));
        stage.show();
    }

    private class MyListCell extends ListCell<String> {

        public MyListCell() {

            setOnDragDetected(event -> {

                if (getItem() == null) {
                    return;
                }

                if (event.getButton() == MouseButton.PRIMARY) {
                    WritableImage image = snapshot(new SnapshotParameters(), null);
                    Dragboard dragboard = startDragAndDrop(TransferMode.MOVE);
                    ClipboardContent content = new ClipboardContent();
                    content.putString("abc");
                    dragboard.setDragView(image);
                    dragboard.setContent(content);
                    //setCursor(Cursor.HAND);
                    event.consume();
                }
            });

            setOnDragOver(event -> {
                if (event.getGestureSource() != this && event.getDragboard().hasString()) {
                    event.acceptTransferModes(TransferMode.MOVE);
                }
                event.consume();
            });

            setOnDragEntered(event -> {
                if (event.getGestureSource() != this && event.getDragboard().hasString()) {
                    setOpacity(0.3);
                }
            });

            setOnDragExited(event -> {
                if (event.getGestureSource() != this && event.getDragboard().hasString()) {
                    setOpacity(1);
                }
            });

            setOnDragDropped(event -> {
                if (getItem() == null) {
                    return;
                }

                Dragboard db = event.getDragboard();
                boolean success = false;

                if (db.hasString()) {

                    ObservableList<String> items = getListView().getItems();
                    String source = ((MyListCell) event.getGestureSource()).getItem();
                    String target = ((MyListCell) event.getGestureTarget()).getItem();

                    int sourceIdx = items.indexOf(source);
                    int targetIdx = items.indexOf(target);

                    //swap
                    items.set(sourceIdx, target);
                    items.set(targetIdx, source);

                    success = true;
                }

                event.setDropCompleted(success);
                event.consume();
            });

            setOnDragDone(DragEvent::consume);
        }

        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                setText(null);
            } else {
                setText(item);
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}

回答1:


OK, I think understand my misunderstanding now. JavaFX supports both a DragView and a Cursor and it displays them both at the same time. So what I think what you are asking is how to show either only the DragView or both the DragView and a custom cursor.

One way to do this is to modify the answer to: How to create a reorder-able TableView in JavaFx, with the following changes:

private ImageCursor dragCursor;
. . .
// inside start()
dragCursor = new ImageCursor(
    new Image(
        "https://cdn2.iconfinder.com/data/icons/web/512/Cursor-512.png", 
        32, 32, true, true
    )
);
// at the end of setOnDragDetected()
getScene().setCursor(dragCursor);
// change setOnDragDone() to:
setOnDragDone(event -> {
    event.consume();
    getScene().setCursor(Cursor.DEFAULT);
});

If you want no cursor rather than a custom image cursor, then you can just call:

getScene().setCursor(Cursor.NONE);

I tested the program on OS X and it worked for me there, your mileage may vary. Note that cursor handling may differ across operating systems (for instance, without the changes in this answer, on OS X, when dragging, I don't get the cursor with box that you are seeing on Windows, I just get a default arrow cursor in addition to the DragView image).

The changes above seem to work as long as you are dragging around the object within the scene. If you drag outside the stage, then the cursor reverts back to the default cursor (I don't have a fix for that as JavaFX does not allow control of the cursor once it passes outside the scene).



来源:https://stackoverflow.com/questions/40982787/change-cursor-in-javafx-listview-during-drag-and-drop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!