9

古いJavaアプリをswingからjavafxに変換していますが、問題が発生しています。

次のコードを使用してスクリーンショットをキャプチャしています。

 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)

これは、次のデバッグ警告が示唆するように、OSX でヘッドレス モードで実行されているように見える javafx と関係があると思います。

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

4

2 に答える 2

6

JavaFX は AWT スタックを使用しないため、純粋な JavaFX アプリケーションでは開始されません。スレッド処理の詳細により、AWT は Mac でヘッドレス モードで実行され、JavaFX から要求されます。

それを解決する次のオプションがあります。

  1. AWT を初期化するためにいくつかのブードゥー教の魔法を使用します -- 静的初期化実行java.awt.Toolkit.getDefaultToolkit(); EDITで、これは古い 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. 編集アレクサンダーが指摘した別の方法は、別の VM で AWT コードを実行することです。これを実現するには、スクリーンショット機能を別のクラスにリファクタリングし、次の方法で JavaFX アプリから呼び出すことができます。

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

    このアプリは、スクリーンショットをファイルシステムに保存できます。スクリーンショットを頻繁に作成する必要があり、パフォーマンスの問題が発生した場合は、その別のアプリを一度実行して、ソケットを介して通信できます。

  4. com.sun.glass.ui.Robotの代わりに使用AWTRobot

于 2013-03-10T11:16:58.887 に答える
3

注意が必要な可能性のある次の事項が表示されます。

  1. Sergey Grinev のポイント 1. set に加えてjavafx.macosx.embedded:

    System.setProperty("javafx.macosx.embedded", "true");
    java.awt.Toolkit.getDefaultToolkit();
    
  2. AWT は EDT で実行され、JavaFX は JavaFX アプリケーション スレッドで実行されることに注意してください。

最近、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);
    }

}
于 2013-03-26T00:04:03.633 に答える