2013-03-10 22 views
9

Sto convertendo la mia vecchia app java da swing a javafx e sto riscontrando un problema.Eccezione headless screencapture JavaFX su OSX

Sto utilizzando il seguente codice per catturare screenshot:

public ScreenCapper() { 
    ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
    gs = ge.getScreenDevices(); 

    try { 
     robot = new Robot(gs[gs.length-1]); 
    } catch (AWTException e) { 
     LOGGER.getInstance().ERROR("Error creating screenshot robot instance!"); 
    } 
} 

public Color capture() { 
    Rectangle bounds; 

    mode = gs[0].getDisplayMode(); 
    bounds = new Rectangle(0, 0, mode.getWidth(), mode.getHeight()); 
    //...... 
} 

Questo funziona bene quando si esegue l'applicazione in Windows. Tuttavia durante l'esecuzione in OSX nel ottenere la seguente eccezione:

Exception in Application start method 
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method 
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:403) 
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47) 
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115) 
at java.lang.Thread.run(Thread.java:722) 
Caused by: java.awt.HeadlessException 
at sun.java2d.HeadlessGraphicsEnvironment.getScreenDevices(HeadlessGraphicsEnvironment.java:72) 
at be.beeles_place.roggbiv.utils.ScreenCapper.<init>(ScreenCapper.java:33) 
at be.beeles_place.roggbiv.modes.AverageColorMode.start(AverageColorMode.java:31) 
at be.beeles_place.roggbiv.modes.ColorModeContext.startCurrentColorMode(ColorModeContext.java:28) 
at be.beeles_place.roggbiv.controller.RoggbivController.<init>(RoggbivController.java:42) 
at be.beeles_place.roggbiv.RoggbivMain.start(RoggbivMain.java:67) 
at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319) 
at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:215) 
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:179) 
at com.sun.javafx.application.PlatformImpl$4$1.run(PlatformImpl.java:176) 
at java.security.AccessController.doPrivileged(Native Method) 
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:176) 
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:76) 

Questo credo ha todo con JavaFX appearently esecuzione è la modalità headless su OSX, come i seguenti avvisi di debug suggeriscono: c'è qualche

013-03-10 10:44:03.795 java[1912:5903] *** WARNING: Method userSpaceScaleFactor in class NSView is deprecated on 10.7 and later. It should not be used in new applications. Use convertRectToBacking: instead. 
2013-03-10 10:44:05.472 java[1912:707] [JRSAppKitAWT markAppIsDaemon]: Process manager already initialized: can't fully enable headless mode. 

Is modo per farlo funzionare? O un altro modo per catturare schermate che non sono in conflitto con OSX?

codice completo @https://github.com/beele/Roggbiv

+1

* "Questo credo ha todo con JavaFX appearently esecuzione è la modalità headless su OSX" * Perché mai sarebbe farlo? È un toolkit GUI e non sono molto utili senza uno schermo. –

+0

Non lo so, ho aggiunto un controllo nel codice sul controllo github per GraphicsEnvironment.isHeadless() e che restituisce true, quindi ... – Beele

risposta

6

JavaFX non usa pila AWT, quindi non è in fase di avvio in pura applicazione JavaFX. A causa delle specifiche di gestione dei thread, AWT viene eseguito in modalità headless su Mac, quindi richiesto da JavaFX.

Non ci sono prossimi opzioni per risolvere che:

  1. usare qualche magia voodoo per inizializzare AWT - in inizializzazione statica java.awt.Toolkit.getDefaultToolkit();EDIT questo ha funzionato solo in anziani JavaFX, scusate

  2. Meglio le opzioni consistono nel rinunciare all'uso di AWT da JavaFX. È possibile utilizzare la prossima funzionalità per fare screenshot: http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#snapshot%28javafx.util.Callback,%20javafx.scene.SnapshotParameters,%20javafx.scene.image.WritableImage%29

  3. EDIT Come Alexander ha sottolineato un altro modo è quello di eseguire il codice AWT in una VM separato. Per ottenere che si può refactoring la funzionalità screenshot ad una classe separata e chiamare da JavaFX app:

    new ProcessBuilder(
          System.getProperty("java.home") + "/bin/java", 
          "-cp", "classpath", 
          "my.apps.DoScreenshot" 
        ).start(); 
    

    Questa applicazione può memorizzare screenshot ad un file system. Se è necessario eseguire spesso schermate e si sono verificati problemi di prestazioni, è possibile eseguire l'app separata una sola volta e comunicare con essa tramite il socket.

  4. Uso com.sun.glass.ui.Robot invece di AWTRobot

+0

L'opzione 1 nasconde gli avvisi che sto ricevendo all'avvio, ma ora il l'intera app javafx non verrà visualizzata sullo schermo. L'opzione 2 non è ciò di cui ho bisogno, immagino. Trasforma parti dell'interfaccia in un'immagine. Ho bisogno di catturare l'intero desktop, non una parte dell'applicazione. Immagino per ora che non ci sia alcuna opzione per farlo funzionare su osx ... – Beele

+0

È possibile fare uno screenshot su mac os, non preoccuparti. La risposta esiste. –

+0

@Beele quale versione di JavaFX usi? –

3

compaiono i seguenti cose che possono avere bisogno di attenzione:

  1. Oltre al punto 1. di Sergey Grinev set javafx.macosx.embedded:

    System.setProperty("javafx.macosx.embedded", "true"); 
    java.awt.Toolkit.getDefaultToolkit(); 
    
  2. Take cura che le cose AWT siano fatte nell'EDT e le cose JavaFX siano fatte nel thread dell'applicazione JavaFX.

Ho avuto a che fare con problemi JavaFX/Swing su un Mac recentemente, quindi questo mi ha interessato. Se provi il codice qui sotto, funziona per te?(Si dovrebbe mettere un colpo di schermo in scala come sfondo della finestra di app.)

import java.awt.AWTException; 
import java.awt.DisplayMode; 
import java.awt.GraphicsDevice; 
import java.awt.GraphicsEnvironment; 
import java.awt.Rectangle; 
import java.awt.Robot; 
import java.awt.image.BufferedImage; 

import javafx.application.Application; 
import javafx.application.Platform; 
import javafx.embed.swing.SwingFXUtils; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.image.Image; 
import javafx.scene.image.ImageView; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

import javax.swing.SwingUtilities; 

public class SO extends Application { 

    @Override 
    public void start(Stage stage) throws Exception { 
     final Pane pane = new StackPane(); 
     Scene scene = new Scene(pane, 600, 300); 
     stage.setScene(scene); 
     Button b = new Button("Snap"); 
     final ImageView iv = new ImageView(); 
     iv.fitWidthProperty().bind(pane.widthProperty()); 
     iv.fitHeightProperty().bind(pane.heightProperty()); 
     pane.getChildren().add(iv); 
     pane.getChildren().add(b); 
     b.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         doSnap(iv); 
        } 
       }); 
      } 
     }); 
     stage.show(); 
    } 

    protected void doSnap(final ImageView iv) { 
     GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); 
     GraphicsDevice[] gs = ge.getScreenDevices(); 

     Robot robot = null; 
     try { 
      robot = new Robot(gs[gs.length-1]); 
     } catch (AWTException e) { 
      e.printStackTrace(); 
      return; 
     } 
     DisplayMode mode = gs[0].getDisplayMode(); 
     Rectangle bounds = new Rectangle(0, 0, mode.getWidth(), mode.getHeight()); 
     final BufferedImage bi = robot.createScreenCapture(bounds); 
     Platform.runLater(new Runnable() { 
      @Override 
      public void run() { 
       Image im = SwingFXUtils.toFXImage(bi, null); 
       iv.setImage(im); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     System.setProperty("javafx.macosx.embedded", "true"); 
     java.awt.Toolkit.getDefaultToolkit(); 
     Application.launch(args); 
    } 

}