JavaFX创建一个小的实时预览窗格

JavaFX创建一个小的实时预览窗格,java,javafx,preview,Java,Javafx,Preview,我有一个项目,我有两个窗口,基本上你可以在演示模式下将其与powerpoint进行比较。在我的一个窗口中,我想在整个第二个窗口的一角显示一个小预览。如果有一个节点的复制方法,我想我可以设法实现它,但我找不到任何方法 为了更好地理解,我试图把我的问题形象化 您可以随时连续拍摄另一个舞台场景(或任意节点)的快照,并将其显示在“实时图像”区域中。下面是一个例子: Main.java import javafx.application.Application; import javafx.fxml.FX

我有一个项目,我有两个窗口,基本上你可以在演示模式下将其与powerpoint进行比较。在我的一个窗口中,我想在整个第二个窗口的一角显示一个小预览。如果有一个节点的复制方法,我想我可以设法实现它,但我找不到任何方法

为了更好地理解,我试图把我的问题形象化


您可以随时连续拍摄另一个
舞台
场景
(或任意
节点
)的快照,并将其显示在“实时图像”区域中。下面是一个例子:

Main.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
    Scene scene = new Scene(loader.load());
    primaryStage.setScene(scene);
    primaryStage.setTitle("Main Window");
    primaryStage.setResizable(false);
    primaryStage.show();
    ((MainController) loader.getController()).displayOtherWindow();
  }

}
import java.io.IOException;
import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class MainController {

  @FXML
  private ImageView imageView;
  private AnimationTimer imageTimer;

  public void displayOtherWindow() throws IOException {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Other.fxml"));
    Scene scene = new Scene(loader.load(), 500, 300);

    Stage stage = new Stage();
    stage.setScene(scene);
    stage.setTitle("Other Window");
    stage.setResizable(false);
    stage.show();

    ((OtherController) loader.getController()).startAnimation();

    imageTimer = new ScreenshotsAnimationTimer(scene);
    imageTimer.start();
  }

  private class ScreenshotsAnimationTimer extends AnimationTimer {

    private final Scene scene;

    private ScreenshotsAnimationTimer(Scene scene) {
      this.scene = scene;
    }

    @Override
    public void handle(long now) {
      imageView.setImage(scene.snapshot(null));
    }

  }
}
import javafx.animation.Animation;
import javafx.animation.SequentialTransition;
import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

public class OtherController {

  @FXML
  private Rectangle rect;

  public void startAnimation() {
    SequentialTransition transition = new SequentialTransition(
        createTransition(500 - rect.getWidth(), 0),
        createTransition(500 - rect.getWidth(), 300 - rect.getHeight()),
        createTransition(0, 300 - rect.getHeight()),
        createTransition(0, 0)
    );
    transition.setCycleCount(Animation.INDEFINITE);
    transition.play();
  }

  private TranslateTransition createTransition(double x, double y) {
    TranslateTransition tt = new TranslateTransition(Duration.seconds(1), rect);
    tt.setToX(x);
    tt.setToY(y);
    return tt;
  }

}
MainController.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
    Scene scene = new Scene(loader.load());
    primaryStage.setScene(scene);
    primaryStage.setTitle("Main Window");
    primaryStage.setResizable(false);
    primaryStage.show();
    ((MainController) loader.getController()).displayOtherWindow();
  }

}
import java.io.IOException;
import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class MainController {

  @FXML
  private ImageView imageView;
  private AnimationTimer imageTimer;

  public void displayOtherWindow() throws IOException {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Other.fxml"));
    Scene scene = new Scene(loader.load(), 500, 300);

    Stage stage = new Stage();
    stage.setScene(scene);
    stage.setTitle("Other Window");
    stage.setResizable(false);
    stage.show();

    ((OtherController) loader.getController()).startAnimation();

    imageTimer = new ScreenshotsAnimationTimer(scene);
    imageTimer.start();
  }

  private class ScreenshotsAnimationTimer extends AnimationTimer {

    private final Scene scene;

    private ScreenshotsAnimationTimer(Scene scene) {
      this.scene = scene;
    }

    @Override
    public void handle(long now) {
      imageView.setImage(scene.snapshot(null));
    }

  }
}
import javafx.animation.Animation;
import javafx.animation.SequentialTransition;
import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

public class OtherController {

  @FXML
  private Rectangle rect;

  public void startAnimation() {
    SequentialTransition transition = new SequentialTransition(
        createTransition(500 - rect.getWidth(), 0),
        createTransition(500 - rect.getWidth(), 300 - rect.getHeight()),
        createTransition(0, 300 - rect.getHeight()),
        createTransition(0, 0)
    );
    transition.setCycleCount(Animation.INDEFINITE);
    transition.play();
  }

  private TranslateTransition createTransition(double x, double y) {
    TranslateTransition tt = new TranslateTransition(Duration.seconds(1), rect);
    tt.setToX(x);
    tt.setToY(y);
    return tt;
  }

}
Main.fxml


othercontroller.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

  @Override
  public void start(Stage primaryStage) throws Exception {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Main.fxml"));
    Scene scene = new Scene(loader.load());
    primaryStage.setScene(scene);
    primaryStage.setTitle("Main Window");
    primaryStage.setResizable(false);
    primaryStage.show();
    ((MainController) loader.getController()).displayOtherWindow();
  }

}
import java.io.IOException;
import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.stage.Stage;

public class MainController {

  @FXML
  private ImageView imageView;
  private AnimationTimer imageTimer;

  public void displayOtherWindow() throws IOException {
    FXMLLoader loader = new FXMLLoader(getClass().getResource("Other.fxml"));
    Scene scene = new Scene(loader.load(), 500, 300);

    Stage stage = new Stage();
    stage.setScene(scene);
    stage.setTitle("Other Window");
    stage.setResizable(false);
    stage.show();

    ((OtherController) loader.getController()).startAnimation();

    imageTimer = new ScreenshotsAnimationTimer(scene);
    imageTimer.start();
  }

  private class ScreenshotsAnimationTimer extends AnimationTimer {

    private final Scene scene;

    private ScreenshotsAnimationTimer(Scene scene) {
      this.scene = scene;
    }

    @Override
    public void handle(long now) {
      imageView.setImage(scene.snapshot(null));
    }

  }
}
import javafx.animation.Animation;
import javafx.animation.SequentialTransition;
import javafx.animation.TranslateTransition;
import javafx.fxml.FXML;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;

public class OtherController {

  @FXML
  private Rectangle rect;

  public void startAnimation() {
    SequentialTransition transition = new SequentialTransition(
        createTransition(500 - rect.getWidth(), 0),
        createTransition(500 - rect.getWidth(), 300 - rect.getHeight()),
        createTransition(0, 300 - rect.getHeight()),
        createTransition(0, 0)
    );
    transition.setCycleCount(Animation.INDEFINITE);
    transition.play();
  }

  private TranslateTransition createTransition(double x, double y) {
    TranslateTransition tt = new TranslateTransition(Duration.seconds(1), rect);
    tt.setToX(x);
    tt.setToY(y);
    return tt;
  }

}
Other.fxml


结果图像


我确实注意到在尝试移动
窗口时出现了一些口吃。更复杂的应用程序也可能导致一些延迟。换句话说,您应该根据应用程序的性能进行调整。例如,你真的需要每帧截图吗?也许你可以每隔一帧或每隔一帧拍摄一次屏幕截图。另一种可能的优化是对快照使用相同的
可写图像
(仅当
场景
的尺寸发生变化时才创建新图像)


还要注意,在我的示例中,我使用了很多硬编码值。您需要为实际应用程序更改此设置。

根据需要,尝试在较大的窗格上布局缩略图大小的简单窗格。当遇到困难时,请在此发布您的尝试(请参阅)。快照节点始终是一种可能,但如果您经常这样做,则很可能会出现内存问题。另一种方法是为两个窗口创建相同的节点类型并进行一些绑定。