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();
修复了它
我有一个带有 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();
修复了它