2016-05-22 12 views
-2

ファイルの場所を取得し、ファイルの情報を表示するためにステージ上のいくつかの要素を非表示にするDrag and Dropを非常に簡単に実装しました。しかし、setVisible()やステージとやりとりする他のコマンドを使用しようとすると、私のプログラムは完全にデッドロックになります。ファイルをドラッグした後にprintlnがあっても問題ないですが、UIを操作するロジックがある瞬間に停止します。DragEventでsetVIsibleメソッドを使用するとJavafxのデッドロックが発生する

これは、ファイルが

"[email protected]" 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) 

にドラッグされた後、デッドロックがここにドラッグイベントを取得最小化メインメソッドで、次のようになります。

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

最小化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

'controller'、どこで何あなたはそれを初期化していますか? –

+0

@James_D申し訳ありませんが、それを含めることを忘れてしまった、私はそれをfxmlファイルのコントローラであるstartメソッドの前に初期化します。 – nmu

+1

startメソッドの前に初期化すると、fxmlファイルのコントローラになることはありません。 fxmlファイルのコントローラは、 'load'を呼び出すときに' FXMLLoader'によって作成されるので、起動メソッドの最初の行が完了するまでインスタンス化されていません。 –

答えて

1

Controller controller = new Controller();で手作業で作成したControllerのインスタンスでbuttonが決して初期化されないため、何かをウィンドウにドロップすると、コードによってNULLポインタ例外が生成されます。

fxmlファイルで定義された要素は、load()を呼び出すとFXMLLoaderに関連付けられたコントローラインスタンスで初期化されます。だからここでやろうとしていることは、そのコントローラオブジェクトにアクセスすることだと思います。 (あなたが新しいものを作成する理由を私は知らない。)あなたが代わりに静的な負荷方法を使用しての、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(); 
     } 
    }); 

    // ... 

} 
+0

コントローラーのfxmlローダーインスタンスを使ってくれてありがとう、私はJavafxにはかなり新しいので、私は静的オブジェクトがトリックをやると仮定しました。私はまたあなたにそれがnullPointerだったことを示すことが好奇心です。私はデバッグ出力で間違ったスレッドを見ていましたか?助けてくれてありがとう! – nmu

+0

あなたは何を見ているのか分かりません:私はちょうどそれ(デバッガなし)を走らせました、そして、(期待通りに)コンソールにヌルポインタ例外がありました。 "私は静的オブジェクトはトリックを行うだろうと仮定した"とは何を意味しているのかわからない:あなたは静的な変数を持っていない(それは[あなたがしたら助けにならない](http://stackoverflow.com/questions/23105433 ))。 –

関連する問題