Как я могу правильно установить курсор мыши во время перетаскивания TitledPane между двумя аккордеонами в Javafx

#javafx #drag-and-drop #mouseevent #javafx-8

#javafx #перетаскивание #mouseevent #javafx-8

Вопрос:

В следующем примере кода обрабатывается перетаскивание TitledPanes между двумя аккордеонными панелями. Перетаскивание работает нормально, но проблема заключается в правильной настройке указателя мыши. При перетаскивании курсор устанавливается правильно. И после завершения перетаскивания курсор устанавливается по умолчанию в большинстве частей. Исключения относятся к заголовку TitledPane, где курсор ПЕРЕМЕЩЕНИЯ все еще установлен. Событие DragDetected, похоже, находится в каком-то внутреннем классе TitledPane, см. Распечатку события ниже. Разве это не должно работать или что я здесь делаю не так?

 package javafxapplication4;

import java.util.function.Consumer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Accordion;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TitledPane;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Background;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 *
 * @author Daniel
 */
public class JavaFXApplication4 extends Application {

    @Override
    public void start(Stage primaryStage) {
        StackPane root = new StackPane();
        HBox hb = new HBox();
        VBox vb1 = new VBox();
        VBox vb2 = new VBox();
        vb1.setPrefHeight(200);
        vb2.setPrefHeight(200);
        Label l1 = new Label("L1");
        Label l2 = new Label("L2");
        Accordion ac1 = new Accordion();
        ac1.setPrefSize(100, 200);
        Accordion ac2 = new Accordion();
        ac2.setPrefSize(100, 200);
        TextArea ta1 = new TextArea();
        TitledPane tp1 = new TitledPane("TP1", ta1);
        ac1.getPanes().add(tp1);
        TextArea ta2 = new TextArea();
        TitledPane tp2 = new TitledPane("TP2", ta2);
        ac2.getPanes().add(tp2);
        vb1.getChildren().add(l1);
        vb2.getChildren().add(l2);
        vb1.getChildren().add(ac1);
        vb2.getChildren().add(ac2);
        hb.getChildren().add(vb1);
        hb.getChildren().add(vb2);

        ac1.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragEntered "   event.toString());
                Consumer<Node> se = s -> s.setMouseTransparent(true);
                ac1.getPanes().forEach(se);
                event.consume();
            }
        });

        ac1.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragExited "   event.toString());
                Consumer<Node> se = s -> s.setMouseTransparent(false);
                ac1.getPanes().forEach(se);
                event.consume();
            }
        });

        ac1.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragReleased "   event.toString());
                TitledPane node = (TitledPane) event.getGestureSource();
                Accordion parent = (Accordion) node.getParent();
                parent.getPanes().remove(node);
                Accordion newParent = (Accordion) event.getTarget();
                newParent.getPanes().add(node);
                ((Node) event.getGestureSource()).setCursor(Cursor.DEFAULT);

                event.consume();
            }
        });
        ac2.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragEntered "   event.toString());
                Consumer<Node> se = s -> s.setMouseTransparent(true);
                ac2.getPanes().forEach(se);
                event.consume();
            }
        });

        ac2.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragExited "   event.toString());
                Consumer<Node> se = s -> s.setMouseTransparent(false);
                ac2.getPanes().forEach(se);
                event.consume();
            }
        });

        ac2.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("dragReleased "   event.toString());
                TitledPane node = (TitledPane) event.getGestureSource();
                Accordion parent = (Accordion) node.getParent();
                parent.getPanes().remove(node);
                Accordion newParent = (Accordion) event.getTarget();
                newParent.getPanes().add(node);
                ((Node) event.getGestureSource()).setCursor(Cursor.DEFAULT);

                event.consume();
            }
        });

        tp1.setOnDragDetected(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("handle dragDetected "   event);
                tp1.startFullDrag();
                ((Node) event.getTarget()).setCursor(Cursor.MOVE);
                //tp1.setCursor(Cursor.MOVE); // Doesn't work - default cursor
                event.consume();
            }

        });
        tp1.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("TitledPane mouseDragReleased "   event);
                TitledPane node = (TitledPane) event.getGestureSource();
                Accordion parent = (Accordion) node.getParent();
                parent.getPanes().remove(node);
                Accordion newParent = (Accordion) ((TitledPane) event.getSource()).getParent();
                newParent.getPanes().add(node);
                event.consume();
            }
        });
        tp2.setOnDragDetected(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                System.out.println("handle dragDetected "   event);
                ((Node) event.getTarget()).setCursor(Cursor.MOVE);
                //tp2.setCursor(Cursor.MOVE);// Doesn't work - default cursor
                tp2.startFullDrag();
                event.consume();
            }

        });
        tp2.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
            @Override
            public void handle(MouseDragEvent event) {
                System.out.println("TitledPane mouseDragReleased "   event);
                TitledPane node = (TitledPane) event.getGestureSource();
                Accordion parent = (Accordion) node.getParent();
                parent.getPanes().remove(node);
                Accordion newParent = (Accordion) ((TitledPane) event.getSource()).getParent();
                newParent.getPanes().add(node);
                event.consume();
            }
        });
        root.getChildren().add(hb);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Drag drop mouse cursor example");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}
 

Он выдает этот вывод для перетаскивания:

 handle dragDetected MouseEvent [source = TitledPane@44ce2e46[styleClass=titled-pane first-titled-pane]'TP1', target = TitledPaneSkin$TitleRegion@451c360f[styleClass=title], eventType = DRAG_DETECTED, consumed = false, x = 71.0, y = 4.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TitledPaneSkin$TitleRegion@451c360f[styleClass=title], point = Point3D [x = 71.0, y = 4.0, z = 0.0], distance = 466.5063509461097]
dragEntered MouseDragEvent [source = Accordion@19ef71a8[styleClass=accordion], target = Accordion@19ef71a8[styleClass=accordion], gestureSource = TitledPane@44ce2e46[styleClass=titled-pane first-titled-pane]'TP1', eventType = MOUSE-DRAG_ENTERED, consumed = false, x = 71.0, y = 4.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TitledPaneSkin$TitleRegion@451c360f[styleClass=title], point = Point3D [x = 71.0, y = 4.0, z = 0.0], distance = 466.5063509461097]
dragExited MouseDragEvent [source = Accordion@19ef71a8[styleClass=accordion], target = Accordion@19ef71a8[styleClass=accordion], gestureSource = TitledPane@44ce2e46[styleClass=titled-pane first-titled-pane]'TP1', eventType = MOUSE-DRAG_EXITED, consumed = false, x = 108.0, y = 3.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TitledPaneSkin$TitleRegion@1f91afb1[styleClass=title], point = Point3D [x = 8.0, y = 3.0, z = 0.0], distance = 466.5063509461097]
dragEntered MouseDragEvent [source = Accordion@77b6ca53[styleClass=accordion], target = Accordion@77b6ca53[styleClass=accordion], gestureSource = TitledPane@44ce2e46[styleClass=titled-pane first-titled-pane]'TP1', eventType = MOUSE-DRAG_ENTERED, consumed = false, x = 8.0, y = 3.0, z = 0.0, button = PRIMARY, primaryButtonDown, pickResult = PickResult [node = TitledPaneSkin$TitleRegion@1f91afb1[styleClass=title], point = Point3D [x = 8.0, y = 3.0, z = 0.0], distance = 466.5063509461097]
dragReleased MouseDragEvent [source = Accordion@77b6ca53[styleClass=accordion], target = Accordion@77b6ca53[styleClass=accordion], gestureSource = TitledPane@44ce2e46[styleClass=titled-pane first-titled-pane]'TP1', eventType = MOUSE-DRAG_RELEASED, consumed = false, x = 70.0, y = 64.0, z = 0.0, button = PRIMARY, pickResult = PickResult [node = Accordion@77b6ca53[styleClass=accordion], point = Point3D [x = 70.0, y = 64.0, z = 0.0], distance = 466.5063509461097]
dragExited MouseDragEvent [source = Accordion@77b6ca53[styleClass=accordion], target = Accordion@77b6ca53[styleClass=accordion], gestureSource = TitledPane@44ce2e46[styleClass=titled-pane]'TP1', eventType = MOUSE-DRAG_EXITED, consumed = false, x = 70.0, y = 64.0, z = 0.0, button = PRIMARY, pickResult = PickResult [node = Accordion@77b6ca53[styleClass=accordion], point = Point3D [x = 70.0, y = 64.0, z = 0.0], distance = 466.5063509461097]
 

Странная часть target = TitledPaneSkin $TitleRegion @451c360f[styleClass=title]
Я бы ожидал, что там будет TitledPane.
Я думаю, что это причина, по которой курсор мыши не сбрасывается должным образом.

Комментарии:

1. Я вижу курсор ПЕРЕМЕЩЕНИЯ, даже когда я навожу курсор на любую из TitledPane. Ожидается ли это?

2. Нет, это не то, чего я ожидал

3. Я нашел уродливый способ решить эту проблему. Добавив это к обоим dragReleasedHandlers: Consumer<Node> g = t -> t.setCursor(Cursor.HAND); ((TitledPane) event.getGestureSource()).getChildrenUnmodifiable().forEach(g); Но это кажется довольно уродливым решением, поэтому я предполагаю, что есть более правильный способ сделать это.