2013-03-10 12 views
9

Konwertuję moją starą aplikację java z wersji na javafx i mam problem.Wyjątkowy nagłówek JavaFX screencapture na OSX

Używam następujący kod do przechwytywania zrzutów ekranu:

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()); 
    //...... 
} 

Działa to dobrze podczas uruchamiania aplikacji w systemie Windows. Jednak podczas jazdy pod OSX w uzyskać następujący wyjątek:

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) 

Ma to myślę todo z JavaFX appearently uruchomiony jest tryb bezgłowy na OSX, jak poniższe ostrzeżenia debugowania sugerują:

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. 

Czy istnieje sposób, aby to zadziałało? Lub inny sposób na przechwytywanie zrzutów ekranu, które nie są sprzeczne z OSX?

pełny kod @https://github.com/beele/Roggbiv

+1

* „To myślę ma todo z JavaFX appearently uruchomiony jest tryb bezgłowe na OSX” * Dlaczego na Ziemi byłoby to zrobić? Jest to zestaw narzędzi GUI i nie mają większego znaczenia bez ekranu. –

+0

Nie wiem, dodałem kod do sprawdzania Github dla GraphicsEnvironment.isHeadless(), który zwraca true, więc ... – Beele

Odpowiedz

6

JavaFX nie używa AWT stos, więc to nie jest rozpoczęty w czystej aplikacji JavaFX. Ze względu na specyfikacje obsługi wątków AWT jest uruchamiany w trybie bezgłowym na komputerze Mac, a następnie żądany z JavaFX.

Są kolejne opcje, aby rozwiązać ten:

  1. Użyj jakąś magię voodoo zainicjować AWT - w statycznej inicjalizacji metę java.awt.Toolkit.getDefaultToolkit();EDIT ten pracował tylko w starszej JavaFX, przepraszam

  2. Better opcją byłoby zrezygnowanie z używania AWT z JavaFX. Można użyć następny funkcjonalność, aby screenshoty: 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 Alexander wskazał innym sposobem jest uruchomienie kodu AWT w oddzielnym VM. Aby to osiągnąć można byłaby swoją funkcjonalność screenshot do osobnej klasy i wywołać ją z JavaFX aplikacji przez:

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

    Ta aplikacja może zapisać zrzut ekranu do plików. Jeśli chcesz często robić zrzuty ekranu i napotykać problemy z wydajnością, możesz uruchomić oddzielną aplikację i komunikować się z nią przez gniazdo.

  4. Zastosowanie com.sun.glass.ui.Robot zamiast AWTRobot

+0

Opcja 1 ukrywa ostrzeżenia, które dostaję podczas uruchamiania, ale teraz cała aplikacja javafx nie pojawi się na ekranie. Opcja 2 nie jest tym, czego potrzebuję. Wykazuje części interfejsu do obrazu. Muszę przechwycić cały pulpit, a nie część aplikacji. Domyślam się, że nie ma opcji, aby działało na osx ... – Beele

+0

Możliwe jest zrobienie zrzutu ekranu na Mac OS, nie martw się. Odpowiedź istnieje. –

+0

@Beele jakiej wersji JavaFX używasz? –

3

widzę następujące rzeczy, które mogą wymagać Uwaga:

  1. Oprócz punktu Siergieja Grinev za 1. Ustaw javafx.macosx.embedded:

    System.setProperty("javafx.macosx.embedded", "true"); 
    java.awt.Toolkit.getDefaultToolkit(); 
    
  2. Take należy się upewnić, że rzeczy AWT są robione w EDT i JavaFX rzeczy odbywa się w wątku aplikacji JavaFX.

Miałem ostatnio do czynienia z problemami JavaFX/Swing na komputerze Mac, więc zainteresowało mnie to. Jeśli wypróbujesz poniższy kod, czy działa on dla Ciebie?(Należy umieścić skalowany zrzut ekranu jako tła okna aplikacji.)

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); 
    } 

}