使用带有DragEvent的

时间:2016-05-22 06:15:00

标签: java multithreading javafx

我有一个非常简单的拖放实现,它获取文件位置,然后在舞台上隐藏一些元素以显示有关该文件的信息。但是,每当我尝试使用setVisible()或与舞台交互的任何其他命令时,我的程序就完全陷入僵局。如果我在使用文件拖动后只有一个println它工作正常,但是当我有任何逻辑操纵UI时它就会停止。

这是在

中拖动文件后死锁的样子
"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)

这是获取拖动事件的Minimized Main方法。

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

最小化控制器

package sample;
import javafx.scene.control.Button;

public class Controller {
    public Button buttonTest;
}

Minimized 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>

我想我可以通过将dragEvent分成它自己的线程来处理这个问题但是根据javafx中的并发规则,它无论如何都无法操纵舞台,因为所有的图形都必须在主要的javafxGUI线程。

希望有人能指出我正确的方向,谢谢!

1 个答案:

答案 0 :(得分:1)

当您将某些内容放到窗口上时,您的代码会生成空指针异常,因为button永远不会在您使用Controller手动创建的Controller controller = new Controller();实例中初始化。

当您调用FXMLLoader时,fxml文件中定义的元素将在与load()关联的控制器实例中初始化。所以我认为你在这里要做的是访问控制器对象。 (我不知道你为什么要创建一个新的。)你可以通过创建FXMLLoader实例并在其上调用getController()来实现,而不是使用静态加载方法:

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

    // ...

}