2012-09-01 11 views
10

Devo visualizzare molti dati (in tempo reale) e sto utilizzando JavaFX 2.2. Quindi ho deciso di "pre-visualizzare" i dati prima che venissero inseriti nel thread della GUI.JavaFX: Canvas to Image in thread non GUI

A mio parere il modo più veloce per farlo (con antialiasing ecc.) È lasciare qualche thread NON GUI per generare immagine/bitmap e quindi inserire in thread GUI (quindi l'interfaccia utente è ancora reattiva per l'utente).

Ma non riesco a trovare modo per Conver Canvas all'Immagine e quindi utilizzare:

Image imageToDraw = convert_tmpCanvasToImage(tmpCanvas); 

Platform.runLater(new Runnable() { 

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

Thx per alcune risposte utilizzabili. :-)

btw: Ho creato l'app di prova per mostrare il mio problema.

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

Sono curioso di sapere se hai risolto questo problema, perché sto riscontrando un problema simile nella generazione di grafici fuori thread. –

+0

Si potrebbe guardare questo [approccio] (http://stackoverflow.com/a/44056730/230513) usando 'Task '; si noti che 'GraphicsContext :: getPixelWriter' potrebbe anche essere utile. – trashgod

+0

In alternativa, è possibile comporre in un 'BufferedImage', come mostrato [qui] (https://stackoverflow.com/a/44141878/230513). – trashgod

risposta

3

Usa tela metodo snapshot (...) per creare un WritableImage dalla tela contenuti. ^^ Funziona bene per me.

+2

Naturalmente l'ho provato. Ma il problema è che quell'istantanea può essere presa dopo il rendering di Canvas e ciò può essere fatto solo nella Discussione dell'applicazione (GUI). Quindi non salverò in nessun momento. – user1498611