2012-09-01 6 views
10

Tengo que visualizar muchos datos (en tiempo real) y estoy usando JavaFX 2.2. Así que he decidido "pre-visualizar" los datos antes de que se inserten en el hilo de la GUI.JavaFX: Canvas a Image en un subproceso que no es GUI

En mi opinión, la forma más rápida de hacerlo (con antialliasing etc.) es dejar algo de subproceso NO GUI para generar imagen/mapa de bits y luego colocar hilo GUI (para que la interfaz siga siendo sensible para el usuario).

Pero no encuentro manera de cómo ConVer lienzo de la imagen y luego usar:

Image imageToDraw = convert_tmpCanvasToImage(tmpCanvas); 

Platform.runLater(new Runnable() { 

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

Thx por algunas respuestas utilizables. :-)

por cierto: He hecho una aplicación de prueba para mostrar mi 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

Tengo curiosidad por si acabas resolviendo este problema, ya que me encuentro con un problema similar al generar gráficos fuera de tema. –

+0

Puede consultar este [enfoque] (http://stackoverflow.com/a/44056730/230513) usando 'Tarea '; tenga en cuenta que 'GraphicsContext :: getPixelWriter' también puede ser útil. – trashgod

+0

Alternativamente, puede componer en una 'Imagen Buffered', como se muestra [aquí] (https://stackoverflow.com/a/44141878/230513). – trashgod

Respuesta

3

utilice el método Canvas 'snapshot (...) para crear una WritableImage del contenido de Canvas'. ^^ Funciona bien para mí.

+2

Por supuesto que lo probé. Pero el problema es que esa instantánea puede tomarse después de que se represente el lienzo y eso se puede hacer solo en el hilo de la Aplicación (GUI). Entonces no ahorraré ningún tiempo. – user1498611

Cuestiones relacionadas