【问题标题】:JavaFX create a small live preview of paneJavaFX 创建窗格的小型实时预览
【发布时间】:2018-08-20 07:59:42
【问题描述】:

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

为了更好地理解,我尝试将我的问题形象化。

【问题讨论】:

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

标签: java javafx preview


【解决方案1】:

您可以随时为其他StageScene(或任意Node)拍摄连续快照,并将它们显示在您的“实时图像”区域中。这是一个例子:

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

}

MainController.java

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

  }
}

Main.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.image.ImageView?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
            fx:controller="MainController" prefHeight="300.0" prefWidth="500.0">

    <center>
        <VBox spacing="10" alignment="CENTER_LEFT">
            <padding>
                <Insets topRightBottomLeft="15"/>
            </padding>
            <Label text="Some controls. These buttons do nothing."/>
            <Button text="Button #1"/>
            <Button text="Button #2"/>
            <Button text="Button #3"/>
        </VBox>
    </center>

    <bottom>
        <VBox>
            <Separator/>
            <HBox minHeight="105" maxHeight="105">
                <padding>
                    <Insets topRightBottomLeft="5"/>
                </padding>
                <Label text="Some other information could go here. Live image is to the right."
                       maxWidth="Infinity" HBox.hgrow="ALWAYS" wrapText="true"/>
                <Separator orientation="VERTICAL"/>
                <ImageView fx:id="imageView" fitWidth="166.66" fitHeight="100"/>
            </HBox>
        </VBox>
    </bottom>

</BorderPane>

OtherControler.java

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

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Group?>
<?import javafx.scene.shape.Rectangle?>

<Group xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
       fx:controller="OtherController">

    <Rectangle fx:id="rect" width="200" height="100"/>

</Group>

结果图片


在尝试移动Window 时,我确实注意到了一些口吃。更复杂的应用程序也可能会导致一些滞后。换句话说,您应该针对应用程序的性能进行调整。例如,您真的需要 每个 帧的屏幕截图吗?也许您可以每隔一帧或每n 帧截屏一次。另一种可能的优化是对快照使用相同的WritableImage(仅当Scene 的尺寸发生变化时才创建新图像)。

还要注意,在我的示例中,我使用了很多硬编码值。您需要针对实际应用进行更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多