I have a pretty simple implementation of a Drag and Drop that gets a file location and then hides some elements on the stage to display information about the file. However my program gets completely deadlocked whenever I try use the setVisible() or any other command that interacts with the stage. If i just have a println after the drag with the file it works fine, but the moment I have any logic that manipulates the UI it just stops.
This is what the deadlock looks like, after a file is dragged in
"main@1" prio=5 tid=0x1 nid=NA waiting
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Unsafe.java:-1)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
Here is the Minimised Main method that gets the drag event.
package sample;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.stage.Stage;
import java.io.File;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 300, 275);
scene.setOnDragOver(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
if (db.hasFiles()) {
event.acceptTransferModes(TransferMode.COPY);
} else {
event.consume();
}
}
});
scene.setOnDragDropped(new EventHandler<DragEvent>() {
@Override
public void handle(DragEvent event) {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasFiles()) {
success = true;
String filePath = null;
for (File file:db.getFiles()) {
filePath = file.getAbsolutePath();
System.out.println(filePath);
Controller controller = new Controller();
//Part where it crashes,
controller.buttonTest.setVisible(false);
}
}
event.setDropCompleted(success);
event.consume();
}
});
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The Minimised Controller
package sample;
import javafx.scene.control.Button;
public class Controller {
public Button buttonTest;
}
The Minimised fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sample.Controller">
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
</rowConstraints>
<children>
<Button fx:id="buttonTest" mnemonicParsing="false" text="Test" />
</children>
</GridPane>
I thought I might be able to handle this by splitting the dragEvent into it's own thread but as per the concurrency rules in javafx, it would not be able to manipulate the stage anyway since all graphics must be on the main javafxGUI thread.
Hoping someone can point me in the right direction, thanks!