2012-09-01 12 views
10

多くのデータ(リアルタイム)を視覚化しなければならず、JavaFX 2.2を使用しています。そこで、私はGUIスレッドに挿入する前にデータを「事前可視化」することに決めました。JavaFX:非GUIスレッドのキャンバス画像

私の意見では、アンチエイリアスなどで最も速い方法は、画像/ビットマップを生成してGUIスレッドに入れることです(ユーザーのUIはまだ応答可能です)。

しかし、私はイメージにキャンバスをCONVERする方法方法見つけ、その後、使用することはできません。いくつかの使用可能な答えを

Image imageToDraw = convert_tmpCanvasToImage(tmpCanvas); 

Platform.runLater(new Runnable() { 

      @Override 
      public void run() { 
       canvas.getGraphicsContext2D().drawImage(imageToDraw, data.offsetX, data.offsetY); 
      } 
     }); 

Thxを。 :-)

btw:私は自分の問題を示すためにテストアプリを作った。

package canvasandthreads02; 

import java.util.Random; 
import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.Button; 
import javafx.scene.image.Image; 
import javafx.scene.layout.AnchorPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

public class CanvasAndThreads02 extends Application { 

@Override 
public void start(Stage primaryStage) { 
    Button btn = new Button(); 
    btn.setText("Paint"); 


    final AnchorPane root = new AnchorPane(); 
    final Canvas canvas = new Canvas(900, 800); 
    canvas.setLayoutX(50); 
    canvas.setLayoutY(50); 
    root.getChildren().add(canvas); 
    root.getChildren().add(btn); 

    Scene scene = new Scene(root, 900, 800); 

    primaryStage.setTitle("Painting in JavaFX"); 
    primaryStage.setScene(scene); 
    primaryStage.show(); 

    btn.setOnAction(new EventHandler<ActionEvent>() { 
     @Override 
     public void handle(ActionEvent event) { 
      System.out.println("Start painting"); 
      /** 
      * Start Thread where some data will be visualized 
      */ 
      new Thread(new PainterThread(canvas, new DataToPaint())).start(); 
     } 
    }); 
} 

private class PainterThread implements Runnable{ 
    private final DataToPaint data; 
    private final Canvas canvas; 
    public PainterThread(Canvas canvas, DataToPaint data){ 
     this.canvas = canvas; 
     this.data = data; 
    } 

    @Override 
    public void run() { 
     long currentTimeMillis = System.currentTimeMillis(); 

     Canvas tmpCanvas = new Canvas(data.width, data.height); 
     GraphicsContext graphicsContext2D = tmpCanvas.getGraphicsContext2D(); 
     graphicsContext2D.setFill(data.color;); 
     for (int i = 0; i < data.height; i++) { 
      for (int j = 0; j < data.width; j++) { 
       graphicsContext2D.fillRect(j, i, 1, 1); //draw 1x1 rectangle 
      } 
     } 

     /** 
     * And now I need still in this Thread convert tmpCanvas to Image, 
     * or use some other method to put result to Main GIU Thread using Platform.runLater(...); 
     */ 
     final Image imageToDraw = convert_tmpCanvasToImage(tmpCanvas); 

     System.out.println("Canvas painting: " + (System.currentTimeMillis()-currentTimeMillis)); 
     Platform.runLater(new Runnable() { 

      @Override 
      public void run() { 
       //Start painting\n Canvas painting: 430 \n Time to convert:62 
       //long currentTimeMillis1 = System.currentTimeMillis(); 
       //Image imageToDraw = tmpCanvas.snapshot(null, null); 
       //System.out.println("Time to convert:" + (System.currentTimeMillis()-currentTimeMillis1)); 
       canvas.getGraphicsContext2D().drawImage(imageToDraw, data.offsetX, data.offsetY); 
      } 
     });  
    } 
} 

private class DataToPaint{ 
    double offsetX = 0; 
    double offsetY = 0; 
    Color color; 
    int width = 500; 
    int height = 250; 

    public DataToPaint(){ 
     Random rand = new Random(); 
     color = new Color(rand.nextDouble(), rand.nextDouble(), rand.nextDouble(), rand.nextDouble()); 
     offsetX = rand.nextDouble() * 20; 
     offsetY = rand.nextDouble() * 20; 
    } 
} 

/** 
* @param args the command line arguments 
*/ 
public static void main(String[] args) { 
    launch(args); 
} 
} 
+0

オフスレッドチャートを生成するときに同様の問題に遭遇しているので、この問題を解決したのが不思議です。 –

+0

この[アプローチ](http://stackoverflow.com/a/44056730/230513)では、「タスク」を使用しています。 'GraphicsContext :: getPixelWriter'も使用できることに注意してください。 – trashgod

+0

また、[ここ](https://stackoverflow.com/a/44141878/230513)に示すように、「BufferedImage」で作成することもできます。 – trashgod

答えて

3

キャンバスのコンテンツからWritableImageを作成するためのCanvasのスナップショット(...)メソッドを使用します。 ^^ 私のためにうまく動作します。

+2

もちろん私はそれを試しました。しかし問題は、Canvasがレンダリングされた後にスナップショットを撮ることができることです。これは、アプリケーション(GUI)スレッドだけで実行できます。だから私は時間を節約しません。 – user1498611