JavaFX:为什么拖动的图像尺寸小于原始尺寸?

时间:2021-01-13 13:27:02

标签: java javafx drag-and-drop

我正在尝试为 ListView 实现拖放,其中每个单元格都是一个 GridPane。所以,我只是制作相应 GridPane 的快照并设置为拖动视图。

WritableImage im = rootPane.snapshot(null, null);
dragboard.setDragView(im);

问题是拖动视图图像的大小以某种方式缩小了,我不知道为什么会这样。

enter image description here

我尝试缩放快照图像,但没有成功。

WritableImage writableImage = new WritableImage((int)(5 * getWidth()), (int)(5 * getHeight()));
SnapshotParameters sp =  new SnapshotParameters();
sp.setTransform(Transform.scale(5, 5));
WritableImage im = rootPane.snapshot(sp, writableImage);

谁能解释一下拖动时如何显示实际图像大小。

编辑:

最小的可重现示例。我还注意到拖动视图的大小取决于...场景大小。较大的场景尺寸较低的拖动视图将

public class Launcher extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane pane = new BorderPane();

        ListView<Foo> fooList = new ListView<>();
        pane.setCenter(fooList);
        fooList.setCellFactory(list -> new FooCell());
        fooList.getItems().setAll(List.of(new Foo("1"), new Foo("2"), new Foo("3"), new Foo("4")));

        Scene scene = new Scene(pane, 1400, 900);
        primaryStage.setTitle("Demo");
        primaryStage.setScene(scene);
        primaryStage.setOnCloseRequest(t -> Platform.exit());
        primaryStage.show();
    }

    static class Foo {

        public String a;

        public Foo(String a) {
            this.a = a;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Foo foo = (Foo) o;

            return a.equals(foo.a);
        }

        @Override
        public int hashCode() {
            return a.hashCode();
        }
    }

    static class FooCell extends ListCell<Foo> {

        private AnchorPane rootPane;
        private GridPane gridPane;
        private Region dragHandle;
        private TextField textField;
        private HBox hbox;

        public FooCell() {
            ListCell<Foo> thisCell = this;

            rootPane = new AnchorPane();

            gridPane = new GridPane();
            gridPane.setPrefHeight(40);
            AnchorPane.setTopAnchor(gridPane, 0d);
            AnchorPane.setRightAnchor(gridPane, 0d);
            AnchorPane.setBottomAnchor(gridPane, 0d);
            AnchorPane.setLeftAnchor(gridPane, 0d);
            rootPane.getChildren().setAll(gridPane);

            dragHandle = new Region();
            dragHandle.setMinWidth(30);

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

                ObservableList<Foo> items = getListView().getItems();
                Dragboard dragboard = startDragAndDrop(TransferMode.MOVE);
                ClipboardContent content = new ClipboardContent();
                content.putString(getItem().a);
                dragboard.setDragView(gridPane.snapshot(null, null));
                dragboard.setContent(content);
                event.consume();
            });

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

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

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

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


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

                if (db.hasString()) {
                    ObservableList<Foo> items = getListView().getItems();
                    int draggedIdx = items.indexOf(new Foo(db.getString()));
                    int thisIdx = items.indexOf(getItem());

                    items.set(draggedIdx, getItem());
                    items.set(thisIdx, new Foo(db.getString()));

                    List<Foo> itemscopy = new ArrayList<>(getListView().getItems());
                    getListView().getItems().setAll(itemscopy);
                    success = true;
                }
                event.setDropCompleted(success);

                event.consume();
            });

            setOnDragDone(DragEvent::consume);

            textField = new TextField();
            hbox = new HBox();

            ColumnConstraints col0 = new ColumnConstraints();
            col0.setHgrow(Priority.NEVER);
            gridPane.add(dragHandle, 0, 0, 1, 10);

            ColumnConstraints col1 = new ColumnConstraints();
            col1.setHgrow(Priority.ALWAYS);
            gridPane.add(textField, 1, 0, 1, 1);
            gridPane.add(hbox, 1, 1, 10, 1);

            gridPane.getColumnConstraints().addAll(col0, col1);
        }

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

            if (empty) {
                setGraphic(null);
                return;
            }

            textField.setText(item.a);
            setGraphic(rootPane);
        }
    }
}

EDIT2(发现问题):

是操作系统(或者更准确地说是显示管理器)将拖动的图像缩小。似乎 JavaFX 使用的 GTK 后端对拖动的图像实施了某种限制。如果图像宽度大于 300-350 像素,它将被缩小。我发现这只是试图在我的电子邮件客户端中拖动各种图片。小图像或中图像不会改变,但会缩放较大的图像。我所说的取决于场景大小是正确的,但这里没有魔法。更改场景大小时,也会更改目标节点大小。当它的宽度接近 300px.. 是的,很明显,但我没有注意。

通常我的问题是我想拖动宽度较大但高度较低的图像。这就是为什么缩放看起来如此丑陋/由于超低字体大小而使文本无法阅读的原因。有趣的是,Electron 没有这样的问题。要么 Chromium 不使用 GTK API 进行拖动,要么 DOM 根据定义不存在此类问题。

0 个答案:

没有答案