-2

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!

nmu
  • 1,442
  • 2
  • 20
  • 40
  • 1
    What is `controller` and where are you initializing it? – James_D May 22 '16 at 13:40
  • @James_D sorry forgot to include it, I initialise it before the start method, it's the controller of the fxml file. – nmu May 22 '16 at 14:17
  • 1
    It can't possibly be the controller for the fxml file if you initialize it before the start method. The controller for the fxml file is created by the `FXMLLoader` when you call `load`, so it hasn't even been instantiated until the first line of your start method completes. – James_D May 22 '16 at 14:18
  • @James_D Welp, I have the line `Controller controller = new Controller();` just before, and it seems to be working. – nmu May 22 '16 at 16:40
  • If it's "working", why are you posting a question? It's absolutely obviously not the controller for your FXML file: how can that possibly be the same object that is created by the `FXMLLoader`? My guess is that `button` is `null`, though it's really still just a guess. Create a [MCVE] if you want your question to be answerable. – James_D May 22 '16 at 16:43
  • @James_D well it's not 'working' in the entirety, but yes I can access the controller class. Here is a tiny example. I don't know where to publish it but I hope this is fine https://github.com/spookyuser/Minimial – nmu May 22 '16 at 17:06
  • 1
    Please [edit] your question to include a [MCVE], instead of posting a link. As for accessing the controller **class**, obviously you can do that but it doesn't help. You need to access the actual controller instance, not some other arbitrary object that happens to be the same class. – James_D May 22 '16 at 17:11
  • @James_D done, hope this is correct :) – nmu May 22 '16 at 17:23
  • That just gives a null pointer exception when you drop something. I said about three comments ago "`button` is probably null". – James_D May 22 '16 at 17:36

1 Answers1

1

Your code generates a null pointer exception when you drop something onto the window, because button is never initialized in the instance of Controller that you create by hand with Controller controller = new Controller();.

Elements defined in the fxml file are initialized in the controller instance associated with the FXMLLoader when you call load(). So I think what you are trying to do here is access that controller object. (I don't know why you create a new one.) You can do this by creating an FXMLLoader instance and calling getController() on it, instead of using the static load method:

@Override
public void start(Stage primaryStage) throws Exception{
    FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
    Parent root = loader.load();
    Controller controller = loader.getController();

    // ...

    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();
        }
    });

    // ...

}
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thank you for that, using the fxml loader instance of Controller fixed it, i'm pretty new to Javafx so I just assumed a static object would do the trick. I'm also curious what shows you it was a nullPointer. Was I looking at the wrong thread in the debug output. Thanks again for the help! – nmu May 22 '16 at 18:43
  • No idea what you were looking at: I just ran it (no debugger) and there was a null pointer exception in the console (as expected). Not sure what you mean by "I just assumed a static object would do the trick": you don't have any static variable (it [wouldn't help if you did](http://stackoverflow.com/questions/23105433)). – James_D May 23 '16 at 10:52