2015-07-21 55 views
2

我注意到一個Platform.runLater()在運行後沒有立即更新舞臺/屏幕,所以我猜畫畫正在其他地方或另一個排隊事件中發生。我很好奇在運行完成後,實際繪畫​​或渲染到屏幕的時間或方式是否排隊或發出信號。JavaFX線程什麼時候畫到顯示器上?

以下代碼將打印1.begin, 1.end, 2.begin, 2.end, 3.begin, 3.end到控制檯,但標籤從不顯示1,儘管第二個runLater()等待。

package main; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.concurrent.Task; 
import javafx.geometry.Insets; 
import javafx.scene.Group; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.control.Label; 
import javafx.scene.layout.VBox; 
import javafx.stage.Stage; 

import java.util.concurrent.CountDownLatch; 

public class SmallRunLater extends Application { 

    SimpleStringProperty labelValue = new SimpleStringProperty("0"); 

    @Override 
    public void start(Stage stage) throws InterruptedException { 

     Scene scene = new Scene(new Group()); 
     stage.setWidth(550); 
     stage.setHeight(550); 

     final VBox vbox = new VBox(); 
     vbox.setSpacing(5); 
     vbox.setPadding(new Insets(10, 0, 0, 10)); 

     Label label = new Label(); 
     label.textProperty().bind(labelValue); 
     Button startBtn = new Button("Start"); 
     vbox.getChildren().addAll(startBtn, label); 

     startBtn.setOnAction((action) -> { 
      try { 
       Task task = new Task<Void>() { 
        @Override 
        protected Void call() throws Exception { 
         SmallWork work = new SmallWork(); 
         work.doWork(labelValue); 
         return null; 
        } 
       }; 
       new Thread(task).start(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     }); 

     ((Group) scene.getRoot()).getChildren().addAll(vbox); 

     stage.setScene(scene); 
     stage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

class SmallWork { 

    public void doWork(SimpleStringProperty labelValue) throws InterruptedException { 

     Platform.runLater(() -> { 
      System.out.println("1.begin"); 
      labelValue.set("1"); 
      System.out.println("1.end"); 
     }); 

     runNow(() -> { 
      System.out.println("2.begin"); 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      labelValue.set("2"); 
      System.out.println("2.end"); 
     }); 

     Platform.runLater(() -> { 
      System.out.println("3.begin"); 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      labelValue.set("3"); 
      System.out.println("3.end"); 

     }); 
    } 

    public static void runNow(Runnable r){ 

     final CountDownLatch doneLatch = new CountDownLatch(1); 

     Platform.runLater(() -> { 
      try { 
       r.run(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       doneLatch.countDown(); 
      } 
     }); 

     try { 
      doneLatch.await(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

這個問題是不太一樣的,但它是有點相似,可以幫助你瞭解一點點更好地瞭解JavaFX及其關聯的基於任務的併發設施如何工作[JavaFx:在應用程序執行不同的方法時與消息異步更新UI標籤](http://stackoverflow.com/a/19969793/1155209) – jewelsea

回答

3

是的,你是對的,Platform.runLater()(由名稱所暗示的)不運行的時候了,只是推Runnable到內部隊列中。有一個內部渲染刻度。 Runnable對象將在渲染前的更新滴答中執行。標籤從不顯示「1」的事實與您的runNow()立即在同一個勾號中被調用的事實恰好吻合,因此兩個Runnable對象被推送到同一隊列並在JavaFX內部循環中的同一個勾號中執行。因此,發生以下情況:

  1. 標籤設置爲1
  2. 內螺紋設置爲休眠。這實際上凍結的應用程序,如果你注意到沒有,因爲渲染線程正在睡覺
  3. 標籤設置爲2
  4. 渲染剔發生,所以我們能看到「2」
  5. ...

我試着運行上面的代碼,有時我可以看到1,這意味着兩個Runnable對象被推入不同的刻度。類似的東西:

  1. 標籤設置爲1
  2. 使蜱
  3. ...
相關問題