2013-03-10 50 views
9

我正在將我的舊java應用程序從swing轉換爲javafx,並且遇到問題。OSX上的JavaFX screencapture無頭異常

我用下面的代碼來捕獲屏幕截圖:

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

這運行Windows下的應用程序時工作正常。然而,在出現以下情況例外OSX下運行時:

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) 

這個我覺得有待辦事項使用JavaFX appearently運行的是OSX無頭模式,如下面的調試警告提示:

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. 

有什麼如何讓這個工作?或者另一種方式來捕捉不與OSX衝突的屏幕截圖?

全碼@https://github.com/beele/Roggbiv

+1

*「這個我覺得有待辦事項使用JavaFX appearently運行的是無頭模式在OSX」 *爲什麼地球上會是什麼呢?這是一個GUI工具包,沒有屏幕就沒什麼用處。 – 2013-03-10 09:51:03

+0

我不知道,我已經在github代碼中檢查GraphicsEnvironment.isHeadless()並且返回true,所以... – Beele 2013-03-10 09:55:13

回答

6

JavaFX的不使用AWT棧,因此它沒有被純JavaFX應用程序啓動。由於線程處理的具體細節,AWT在Mac上以無頭模式運行,然後從JavaFX請求。

旁邊有解決方案:

  1. 利用各種巧妙的初始化AWT - 靜態初始化運行java.awt.Toolkit.getDefaultToolkit();編輯這隻曾在年長的JavaFX,對不起

  2. 更好選項將選擇不使用JavaFX的AWT。您可以使用未來的功能,使屏幕截圖:http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html#snapshot%28javafx.util.Callback,%20javafx.scene.SnapshotParameters,%20javafx.scene.image.WritableImage%29

  3. 編輯正如亞歷山大指出的另一種方式是在一個單獨的虛擬機上運行的代碼AWT。爲了實現這一目標,你可以重構你的屏幕截圖功能,以一個單獨的類和程序,通過JavaFX應用程序調用它:

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

    這個程序可以截圖保存到一個文件系統。 如果您需要經常執行屏幕截圖並遇到性能問題,您可以運行一次這個單獨的應用程序並通過套接字與它進行通信。的AWTRobot

+0

選項1隱藏了啓動時發出的警告,但是現在整個javafx應用程序不會顯示在屏幕上。 選項2不是我所需要的。它將界面的一部分渲染爲圖像。我需要捕獲整個桌面,而不是應用程序的一部分。 我想現在沒有辦法讓它在osx上工作...... – Beele 2013-03-10 11:28:47

+0

可以在mac os上截圖,不用擔心。答案是存在的。 – 2013-03-10 12:04:04

+0

@Beele你使用的是什麼版本的JavaFX? – 2013-03-10 12:27:52

3

我看到下面的東西可能需要注意

  • 使用com.sun.glass.ui.Robot代替:

    1. 除了謝爾蓋Grinev的觀點1.設置javafx.macosx.embedded

      System.setProperty("javafx.macosx.embedded", "true"); 
      java.awt.Toolkit.getDefaultToolkit(); 
      
    2. Take關心AWT的東西在EDT中完成,JavaFX的東西在JavaFX Application線程中完成。

    我最近在Mac上處理JavaFX/Swing問題,所以這讓我感興趣。如果您嘗試下面的代碼,它是否適合您?(應該把縮放屏幕截圖作爲應用程序窗口的背景。)

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