当前位置: 首页 > 知识库问答 >
问题:

JavaFX的ImageView中的屏幕共享

充高扬
2023-03-14

我正在尝试构建一个JavaFX应用html" target="_blank">程序,其中我有一个名为“Start”的按钮和一个ImageView。使用JavaFX-12的机器人类,我正在尝试在单击按钮时截取笔记本电脑屏幕的屏幕截图,并在ImageView中的运行时逐一显示图像。我的问题是JavaFX窗口没有响应,程序崩溃(可能)。甚至让线程进入睡眠状态似乎也不起作用。我假设它不起作用,因为我没有设置任何fps规则,但我怎么能这样做呢?目前,我正在创建可写图像,将它们转换为带有数字的单独图像,保存它们,然后再次重复使用它们。我的目标是在图像视图中创建同一台笔记本电脑的屏幕共享。我知道这很难。我是JavaFx机器人类的新手(不是他awt一个)。感谢任何帮助。

注意:这些图片在目录中正确排列。

package sample;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.VBox;
import javafx.scene.robot.Robot;
import javafx.stage.Screen;
import javafx.stage.Stage;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");

        ImageView iv = new ImageView();
        iv.setFitWidth(100);
        iv.setFitHeight(100);
        Button b = new Button("Start");
        VBox v = new VBox(10);
        v.getChildren().addAll(b,iv);
        b.setOnAction(event -> {
            Robot r = new Robot();
            WritableImage wi = new WritableImage(300,300);
            WritableImage i;
            Rectangle2D rect = Screen.getPrimary().getVisualBounds();
            while(true){
                i = r.getScreenCapture(wi,rect);
                try {
                    ImageIO.write(SwingFXUtils.fromFXImage(i,null),"png",new File("F:/Pic/pic" + x + ".png"));
                    iv.setImage(new Image(new FileInputStream("F:/Pic/pic" + x + ".png")));
                    //Thread.sleep(500);
                    //iv.setImage(null);
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        });
        primaryStage.setScene(new Scene(v, 500, 500));
        primaryStage.show();
    }


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

共有1个答案

宓弘壮
2023-03-14

与大多数UI框架一样,JavaFX是单线程的。决不能阻止(例如睡眠)或垄断(例如while(true))JavaFX应用程序线程。该线程负责与UI相关的所有事情,如果它不能自由地完成其工作,则UI将变得无响应。请注意,在FX线程执行任何操作返回之前,渲染过程都不会发生,因此在循环中设置ImageView的图像在循环终止后的一段时间内不会产生可见效果。

此外,全速while循环将尝试以CPU执行所述循环的速度获取屏幕捕获。这可能比用户界面刷新的速度快得多,因此是对资源的浪费。屏幕捕获的速率不应超过帧速率。

如果需要在FX线程上循环和/或受到(JavaFX)帧速率的限制,那么使用JavaFX。动画API。在你的例子中,AnimationTimer似乎很合适。下面是一个持续截屏主屏幕的示例:

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.robot.Robot;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class App extends Application {

  @Override
  public void start(Stage primaryStage) {
    ImageView view = new ImageView();
    view.setFitWidth(720);
    view.setFitHeight(480);

    // Keep a reference to the AnimationTimer instance if
    // you want to be able to start and stop it at will
    new AnimationTimer() {

      final Robot robot = new Robot();
      final Rectangle2D bounds = Screen.getPrimary().getBounds();

      @Override
      public void handle(long now) {
        WritableImage oldImage = (WritableImage) view.getImage();
        WritableImage newImage = robot.getScreenCapture(oldImage, bounds);
        if (oldImage != newImage) {
          view.setImage(newImage);
        }
      }
    }.start();

    primaryStage.setScene(new Scene(new StackPane(view)));
    primaryStage.show();
  }
}

注意:

  • 每帧调用一次AnimationTimer#hand(long)方法。JavaFX尝试以每秒60帧为目标。如果这太快(上面在我的计算机上有些滞后),那么您可以使用该方法的参数,即当前帧的时间戳(以纳秒为单位)来限制屏幕捕获的速率。您还可以考虑使用TimelinePauseTransition而不是AnimationTimer。有关更多信息,请参阅JavaFX定期后台任务。
  • 上面给出了Droste效应(我认为这是术语?),因为屏幕捕获显示在正在捕获的屏幕上。

我的示例不包括将每个图像保存到文件中。您似乎已经理解了如何做到这一点,因此应该能够轻松地修改代码。不过,将I/O移动到后台线程可能是个好主意。不幸的是,这可能需要为每次捕获使用不同的WritableImage实例,以避免FX线程在后台线程读取图像时对图像进行变异。它可能还需要一些调整或删除图像;我不确定I/O能否跟上屏幕截图的涌入(即标准的生产者-消费者问题)。

顺便说一句,你的问题解释了你试图分享整个屏幕。如果是这种情况,则继续使用Robot。但是,如果您只需要共享来自JavaFX应用程序本身的内容,那么可以考虑使用节点#快照(SnapshotParameters,WritableImage)场景#快照(WritableImage)(假设您不能只发送模型数据而不是图像)。

 类似资料:
  • 问题内容: 我想在屏幕上居中放置一个舞台。 这是我尝试过的: 调用centerOnScreen()后,舞台过高。它似乎无法正常工作。我需要自己计算x和y pos吗?或者如何正确使用此功能? 问题答案: 的默认实现如下: 哪里 总是将舞台设置为比中心高一点。 要将舞台定位在精确的中心,可以使用您设置的 自定义X和Y值 。

  • 我正在尝试以编程方式添加ImageView,但不要在不同的屏幕上制作相同的大小。我尝试了许多比例代码,但没有任何好的结果。 屏幕:屏幕图像 这是我的代码:

  • 我正在尝试制作一款包含来自存储或网络的无限图像的应用程序。但问题是,recyclerview的滚动速度非常慢 我如何在我的应用程序中创建图像列表,如gallery、whats应用程序、instagram等 我想让我的应用程序运行得非常平稳 请帮帮我! 适配器代码 :

  • 我的有问题,当我在手机上启动应用程序时,它会显示约0.5秒的白色屏幕。扩展了,在中,我声明为启动器,肖像模式为。 代码: XML:

  • 请检查升级最新版本; 若依旧无法看到请尝试退出会议后重新加入,并向我们反馈问题详情

  • 我是JavaFX新手,在做我的项目时,我尝试切换屏幕。我正在考虑相应的AnchorPane可见性设置为真或假,当从另一个控制器访问AnchorPane时,我遇到了问题。我试图使AnchorPane成为静态的,但它给出了NullPointerException。 这是我的密码。 控制器类 SignUpController类 我试图像这样解决问题,但它关闭了窗口并打开了一个新窗口。