2014-07-24 4 views
1

오늘은 JavaFX에 대해 배우기 시작했고 스네이크 클론을 작성하여 자세한 내용을 배우려고했지만 스레딩 문제가 있습니다. 화면에서 뱀의 위치를 ​​업데이트 한 스레드를 만들고 싶었지만 정상적인 Runnable 스레드 방식으로는 사용할 수 없었습니다. 그 스레드 내에서 JavaFX를 사용하여 화면에 그린 직사각형 위치를 업데이트했기 때문에 (내가 배운 할 수 없으며 대신 Tasks, Services, Platform.runLater 등을 사용해야합니까?) JavaFX.scene.layout.Pane을 확장하여 스레드를 생성하는 클래스에서 뱀 위치를 업데이트하는 작업을 사용하려고합니다. . 내 문제는 : 작업은 단 한두 번 실행하고 중단, 나에게 어떤 인터럽트도주지 않고있다. 창을 확장하는 클래스에 대한JavaFX 작업 종료 및 JavaFX 스레딩

생성자 (뱀의 클래스가 확장 그룹) : 내가 실제로 가장 좋은 것은 여기에 무엇을 파악하지 않는 것처럼, 내가하려고 어떤 느낌

public GameFrame(){ 
    this.setPrefSize(800, 600); 

    Snake snake = new Snake(); 
    this.getChildren().add(snake); 

    taskThread = new Thread(new Task<Void>() { 
     protected Void call() throws Exception { 
       while(!Thread.currentThread().isInterrupted()){ 
        snake.updatePosition(); 
        try{ 
        Thread.sleep(1000); 
        } catch(InterruptedException e){ 
         break; 
        } 
       } 
      return null; 
     } 
    }); 
    taskThread.start(); 
} 

do는 hackish일지도 모른다. 내가해야 할 일에 대한 제안이나이를 해결할 수있는 방법이 있습니까?

답변

4

자바 FX에서 스레딩의 기본 규칙은 (이미이 중 일부를 이해한다면 난 그냥 완료하려면, 용서)입니다 : 블록 실행 (또는 시간이 오래 걸리는

  1. 뭐든지 실행) 백그라운드 스레드에서 실행해야합니다 -하지 FX 응용 프로그램 스레드의 FX 응용 프로그램 스레드 위해

을에에서 실행되어야하는 장면 그래프의 일부인 Node의 상태를 변경

  • 아무것도 도움을 얻다. JavaFX API는 Task 클래스를 제공합니다. 이 메서드는 값을 반환하는 call() 메서드를가집니다. Runnable이므로 Thread 생성자에 인수로 제공하거나 Executor으로 전달할 수 있습니다. 또한 FX 응용 프로그램 스레드에서 setOnSucceeded, setOnFailedprogressmessage과 같은 속성을 업데이트하는 다양한 update...() 메서드와 같이 유용한 응용 프로그램 스레드에서 실행되는 유용한 콜백을 제공합니다.

    그러나 실제로는 Task 클래스는 일회성 작업을 위해 설계되었습니다. 데이터베이스에서 데이터를 검색해야하는 응용 프로그램 (예 : 시간이 걸릴 수 있음)을 생각해보십시오. 이들은 특정 동작을 실행하고 결과를 반환합니다. 스레드가 지속적으로 실행된다는 점에서 사례가 다소 다릅니다.

    이 경우 단순한 Thread을 사용하고 Platform.runLater(...)을 사용하여 UI를 업데이트하는 것이 좋습니다. Platform.runLater(...)Runnable이며 FX 응용 프로그램 스레드에서 run() 메서드를 실행합니다.

    당신의 코드가 당신이 묘사하는 것처럼 행동하는 이유는 분명하지 않지만, snake.updatePosition()이라는 메서드 호출이 FX 어플리케이션 스레드에서 실행되어야하는 UI 변경을 야기한다고 가정합니다. 주기적으로 뭔가를 실행하기위한 자바 FX의

    taskThread = new Thread(() -> { 
        while (! Thread.currentThread().isInterrupted()) { 
         Platform.runLater(snake::updatePosition); 
         try { 
          Thread.sleep(1000); 
         } catch (InterruptedException exc) { 
          break ; 
         } 
        } 
    }); 
    

    또 다른 기술 : 자바 8 사용하는 경우 어떤 경우에는 내가이 모든 람다 익명 내부 클래스를 교체와 많이 낫 네요,

    taskThread = new Thread(new Runnable() { 
        public void run() { 
          while(!Thread.currentThread().isInterrupted()){ 
           Platform.runLater(new Runnable() { 
            @Override 
            public void run() { 
             snake.updatePosition(); 
            } 
           }); 
           try{ 
            Thread.sleep(1000); 
           } catch(InterruptedException e){ 
            break; 
           } 
          } 
        } 
    }); 
    

    을 시도 할 것 ~ (ab?) 애니메이션 사용, 자바 8, 다소 매끄러운

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
         new EventHandler<ActionEvent>() { 
          @Override 
          public void handle(ActionEvent event) { 
           snake.updatePosition(); 
          } 
         } 
        )); 
        timeline.setCycleCount(Animation.INDEFINITE); 
        timeline.play(); 
    

    또는

    Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), 
         event -> snake.updatePosition())); 
        timeline.setCycleCount(Animation.INDEFINITE); 
        timeline.play();