ImageViews MouseEvent 不适用于 javaFX 应用程序

ImageViews MouseEvent not working on a javaFX application

我有一个带有 ImageView 的 javaFX 应用程序,我需要做的是能够拖动一个 ImageView,将其放在另一个 ImageView 上,然后用另一个 ImageView 替换它们。 我的问题是我设置的事件对某些 ImageView 有效,但对其他图像无效。

示例:example,我可以将红色箭头图像拖放到绿色上,但不能将绿色拖放到红色上,我不能将绿色箭头图像拖放到其他图像上(两个轴和木头)

我正在从 FXML 文件加载 GUI,这是我的控制器 class :

public class PartieGUI {

    @FXML
    Pane gamePane;

    static ArrayList<ElementGUI> elements = new ArrayList<>() {{
        add( new ElementGUI( "OAK_LOG" ) );
        add( new ElementGUI( "STONE_AXE" ) );
        add( new ElementGUI( "IRON_AXE" ) );
        add( new ElementGUI( "DIAMOND_ORE" ) );
        add( new ElementGUI( "DIAMOND_PICKAXE" ) );
    }};

    private static final int HEIGHT = 100;
    private static final int WIDTH = 100;

    @FXML
    public void initialize() {

        gamePane.setOnDragOver( event -> { // for moving the dragged ImageView
            if( event.getGestureSource() instanceof ImageView ) {
                ImageView draggedImageView = ( (ImageView) event.getGestureSource() );
                draggedImageView.setX( event.getX() - WIDTH / 2 );
                draggedImageView.setY( event.getY() - HEIGHT / 2 );
            }
        } );

        for( ElementGUI elementGUI : elements ) {
            setEvents( elementGUI );
            gamePane.getChildren().add( elementGUI.imageView );
        }

    }

    private void setEvents( ElementGUI elementGUI ) {
        ImageView imageView = elementGUI.imageView;

        imageView.setOnDragDetected( event -> {
            Dragboard db = imageView.startDragAndDrop( TransferMode.ANY );
            ClipboardContent content = new ClipboardContent();
            content.putImage( imageView.getImage() );
            content.putString( elementGUI.ID ); ;
            db.setContent( content );
        } );

        imageView.setOnDragOver( event -> {
            Dragboard db = event.getDragboard();
            if( db.hasImage() && !db.getString().equals( elementGUI.ID ) 
                    && event.getGestureSource() instanceof ImageView ) {
                ImageView draggedImageView = ( (ImageView) event.getGestureSource() );
                if( imageView != draggedImageView ) { // prevent that  it drag and drop on itself
                    System.out.println( "dragging over" );
                    event.acceptTransferModes( TransferMode.ANY );
                }
            }
        } );

        imageView.setOnDragDropped( event -> {
            Dragboard db = event.getDragboard();
            if( db.hasImage() && !db.getString().equals( elementGUI.ID ) 
                    && event.getGestureSource() instanceof ImageView ) {
                ImageView draggedImageView = ( (ImageView) event.getGestureSource() );
                if( imageView == draggedImageView )
                    return;
                elements.removeIf( element -> element.imageView == draggedImageView );
                elements.removeIf( element -> element.imageView == imageView );
                ElementGUI newElement = new ElementGUI( "DIAMOND", imageView.getX(), imageView.getY() );
                setEvents( newElement );
                elements.add( newElement );
                refreshGamePane();
            }
        } );
    }

    public void refreshGamePane() {
        gamePane.getChildren().clear();
        for( ElementGUI elementGUI : elements )
            gamePane.getChildren().add( elementGUI.imageView );
    }

    private static class ElementGUI {

        protected String ID;
        protected ImageView imageView;

        ElementGUI( String ID ) {
            this.ID = ID;
            this.imageView = new ImageView(
                      new Image( PartieGUI.class.getResource( "/Textures/" + ID + ".png" )
                    .toString(), 100, 100, false, false )
            );
            this.imageView.setX( new Random().nextInt( 500 ) ); // tmp
            this.imageView.setY( new Random().nextInt( 200 ) );
        }

        public ElementGUI( String ID, double x, double y ) {
            this.ID = ID;
            this.imageView = new ImageView(
                      new Image( PartieGUI.class.getResource( "/Textures/" + ID + ".png" )
                    .toString(), 100, 100, false , false )
            );
            this.imageView.setX( x );
            this.imageView.setY( y );
        }

    }

}

我的应用程序class,后面是FXML文件,如果你想测试(不要问为什么Pane在BorderPane中,我需要它是这样的)

public class Executor extends Application {
    
    public static void main( String[] args ) {
        launch();
    }

    @Override
    public void start( Stage primaryStage ) throws IOException {
        primaryStage.setScene( new Scene( FXMLLoader.load( 
                Executor.class.getResource( "/GUIs/PartieGUI.fxml" ) 
        ) ) ); // load FXML file
        primaryStage.show();
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.Pane?>

<BorderPane prefHeight="400.0" prefWidth="800.0" style="-fx-background-color: dedddd;" xmlns="http://javafx.com/javafx/15.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="PartieGUI">
   <center>
      <Pane fx:id="gamePane" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
   </center>
</BorderPane>

因为有人说所有这些信息都不足以用于“最小可重现示例”,这里是我使用的图像:https://imgur.com/a/sb3nmKC

还有 build.gradle(我有 JDK 11 个没有集成 javaFX 库,所以我必须使用 gradle):

plugins {
    id 'java'
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.9'
    id "com.github.johnrengelman.shadow" version "6.1.0"
}

repositories {
    mavenCentral()
}

mainClassName = 'Executor'
archivesBaseName = 'MoriaMines'

shadowJar {
    archiveFileName = archivesBaseName + ".jar"
    manifest {
        attributes 'Main-Class': mainClassName
    }
}

javafx {
    version = "15.0.1"
    modules = ['javafx.controls', 'javafx.fxml']
}

kleopatra 的回答:在 setOnDragDetected 中调用 imageView.toBack(); 修复了它