Reputation: 21
I have a javaFX application with ImageView, what i need to do is to be able to drag an ImageView, drop it on an another ImageView and replace them both by an another single ImageView. My problem is that the event i set, work well for some ImageView, but not for others.
Example : example, i can drag and drop the red arrow image on the green, but not the green on the red, I can't drop the green one on the others ( the two axes and the wood )
I'm loading the GUI from a FXML file, here is my controller 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 );
}
}
}
My application class, followed by the FXML file, if you want to test ( don't ask why the Pane is in a BorderPane, i need it to be like this )
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>
Since someone said that all this information is not enought for "minimal reproducible example", here are the images i used : https://imgur.com/a/sb3nmKC
Also the build.gradle ( i have JDK 11 who don't have javaFX libraries integrated, so i must use 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']
}
Upvotes: 0
Views: 176
Reputation: 21
Answer by kleopatra : calling imageView.toBack();
in setOnDragDetected fixed it
Upvotes: 0