Run javafx and swing application at the same time

不打扰是莪最后的温柔 提交于 2019-12-12 01:48:36

问题


I'm using Webcam Capture API in java to access my webcam. Webcam Capture API is built on Swing, I know that, however I want to combine the Webcam Swing class with my JavaFX class. The JavaFX class displays a rectangle on the screen. My goal is: I run my JavaFX class which displays the rectangle on the screen. At some point (e.g. mouse click) I want to start the Webcam. The Webcam is setup to look at the screen and should then do certain things with the images of the rectangle.

JavaFX class:

public class JavaFXDisplay extends Application {

    @Override
    public void start(Stage primaryStage) {
        WebcamCapture wc = new WebcamCapture();

        StackPane root = new StackPane();

        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(500);
        rectangle.setHeight(500);

        Scene scene = new Scene(root, 1000, 1000);
        root.getChildren().addAll(rectangle);

        primaryStage.setScene(scene);
        primaryStage.show();

        scene.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                wc.doSomething();
            }
        });
   }

   public static void main(String[] args) {
       launch(args);
   }
}

Swing class:

public class WebcamCapture extends JFrame implements Runnable, ThreadFactory {

    private static final long serialVersionUID = 6441489157408381878L;

    private Executor executor = Executors.newSingleThreadExecutor(this);

    private Webcam webcam = null;
    private WebcamPanel panel = null;
    private JTextArea textarea = null;

    public WebcamCapture() {
        super();

        setLayout(new FlowLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Dimension size = WebcamResolution.QVGA.getSize();

        webcam = Webcam.getWebcams().get(0);
        webcam.setViewSize(size);

        panel = new WebcamPanel(webcam);
        panel.setPreferredSize(size);

        textarea = new JTextArea();
        textarea.setEditable(false);
        textarea.setPreferredSize(size);

        add(panel);
        add(textarea);

        pack();
        setVisible(true);
    }

    public void doSomething() {
        executor.execute(this);
    }

    @Override
    public void run() {
        do {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            BufferedImage image = null;

            if (webcam.isOpen()) {
                if ((image = webcam.getImage()) == null) {
                    continue;
                }

                doSomeStuff;
            }
        } while (true);
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r, "example-runner");
        t.setDaemon(true);
        return t;
    }

    public static void main(String[] args) {
        new WebcamCapture();
    }
}

However my JavaFX class is not starting/displaying. What is wrong with my code?


回答1:


I'm not familiar with the web cam API you're using (so I don't know if this is the only thing wrong), but you do need to create your Swing content on the AWT event dispatch thread. Currently you are creating it on the FX Application Thread.

You can use the following idiom:

public class JavaFXDisplay extends Application {

    private WebcamCapture wc ;

    @Override
    public void init() throws Exception {
        super.init();
        FutureTask<WebcamCapture> launchWebcam = new FutureTask<>(WebcamCapture::new) ;
        SwingUtilities.invokeLater(launchWebcam);

        // block until webcam is started:
        wc = launchWebcam.get();
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        StackPane root = new StackPane();

        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(500);
        rectangle.setHeight(500);

        Scene scene = new Scene(root, 1000, 1000);
        root.getChildren().addAll(rectangle);

        primaryStage.setScene(scene);
        primaryStage.show();

        scene.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                wc.doSomething();
            }
        });
   }

   public static void main(String[] args) {
       launch(args);
   }
}

For reference, here is a JavaFX-only webcam viewer. I tested this on a MacBookPro running OS X Sierra (10.12.2), with a 2011 27" Thunderbolt display with camera.

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamResolution;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class FXWebCamViewer extends Application {

    private BlockingQueue<Image> imageQueue = new ArrayBlockingQueue<>(5);

    private Executor exec = Executors.newCachedThreadPool(runnable -> {
        Thread t = new Thread(runnable);
        t.setDaemon(true);
        return t ;
    });

    private Webcam webcam;

    @Override
    public void init() {
        webcam = Webcam.getWebcams().get(0);
        Dimension viewSize = WebcamResolution.QVGA.getSize();
        webcam.setViewSize(viewSize);
        webcam.open();
    }

    @Override
    public void start(Stage primaryStage) {
        ImageView imageView = new ImageView();

        StackPane root = new StackPane(imageView);
        imageView.fitWidthProperty().bind(root.widthProperty());
        imageView.fitHeightProperty().bind(root.heightProperty());
        imageView.setPreserveRatio(true);

        AnimationTimer updateImage = new AnimationTimer() {
            @Override
            public void handle(long timestamp) {
                Image image = imageQueue.poll();
                if (image != null) {
                    imageView.setImage(image);
                }
            }
        };
        updateImage.start();

        exec.execute(this::generateImages);

        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void generateImages() {
        while (! Thread.interrupted()) {
            try {
                if (webcam.isOpen() && webcam.isImageNew()) {
                    BufferedImage bimg = webcam.getImage();
                    if (bimg != null) {
                        imageQueue.put(SwingFXUtils.toFXImage(bimg, null));
                    }
                } else {
                    Thread.sleep(250);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}


来源:https://stackoverflow.com/questions/42816859/run-javafx-and-swing-application-at-the-same-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!