【问题标题】:Change cursor in JavaFx ListView during drag and drop在拖放期间更改 JavaFx ListView 中的光标
【发布时间】:2016-12-05 20:31:11
【问题描述】:

我有一个列表视图,我可以在其中通过拖放重新排列元素并且它工作正常,但是我想用我自己的自定义图标替换两个默认图标。我已经尝试在 ListCell 本身或其父级上使用 setCursor(Cursor.HAND) setCursor(new ImageCursor(image)) ,但在拖动过程中没有任何反映,只有在之后,这不是我想要的。有谁知道这个怎么办?

Edit1: 这个问题与如何创建可重新排序的列表视图无关。它是关于如何在列表视图项目的拖放过程中更改默认光标。它不是
How to create a reorder-able TableView in JavaFx 的副本,因为它在拖放过程中也具有相同的默认光标图标。

Edit2:根据我的发现影响 Windows 和 Linux 操作系统,而不是 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);
    }
}

【问题讨论】:

  • @jewelsea 这个问题与如何创建可重新排序的列表视图无关。这是关于如何在列表视图项的拖放过程中更改默认光标。
  • @jewelsea 谢谢,但是我已经尝试了您的示例,并且在拖动时会遇到相同的默认光标(带有框的指针)。看看这个截图link那个光标是我想要改变的。

标签: listview javafx drag-and-drop icons


【解决方案1】:

好的,我想现在理解我的误解了。 JavaFX 支持 DragView 和 Cursor 并同时显示它们。所以我认为您要问的是如何仅显示 DragView 或同时显示 DragView 和自定义光标。

一种方法是将答案修改为:How to create a reorder-able TableView in JavaFx,并进行以下更改:

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

如果您不想要光标而不是自定义图像光标,那么您可以调用:

getScene().setCursor(Cursor.NONE);

我在 OS X 上测试了该程序,它在那里为我工作,你的里程可能会有所不同。请注意,光标处理可能因操作系统而异(例如,在此答案中没有更改,在 OS X 上,拖动时,我没有得到您在 Windows 上看到的带有框的光标,我只是得到一个默认箭头光标除了 DragView 图像)。

只要您在场景中拖动对象,上述更改似乎就可以工作。如果您在舞台外拖动,则光标将恢复为默认光标(我没有解决此问题,因为 JavaFX 不允许在光标通过场景后对其进行控制)。

【讨论】:

  • 谢谢,我现在已经在我的 Mac 上测试过了,它确实可以在 OS X 上工作,但不能在 Linux 和 Windows 上工作,不知何故,这些 OS:es 似乎用自己的默认光标覆盖了自定义光标。真的很烦人,但我想我必须忍受它。
  • @jibilander:你最后在windows PC上找到解决这个问题的方法了吗?我尝试了这个答案:stackoverflow.com/questions/15019645/… ...但我有同样的问题:光标更改但仅在拖放完成后。我想更改拖放事件的默认光标。这让我发疯了
猜你喜欢
  • 2018-12-01
  • 2013-02-02
  • 2022-08-11
  • 2012-01-17
  • 2017-06-09
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
相关资源
最近更新 更多