我有一个非常简单的拖放实现,它获取文件位置,然后在舞台上隐藏一些元素以显示有关该文件的信息。但是,每当我尝试使用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线程。
希望有人能指出我正确的方向,谢谢!
答案 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();
}
});
// ...
}