JavaFX 创建窗格的小型实时预览
JavaFX create a small live preview of pane
我有一个项目,其中有两个 windows,基本上您可以将它与演示模式下的 powerpoint 进行比较。在我的一个 windows 中,我想在整个第二个 window 中显示的内容的一角显示一个小预览。如果有节点的复制方法,我想我可以设法实现它,但我找不到。
为了更好地理解我尝试形象化我的问题。
您可以随时拍摄其他 Stage
的 Scene
(或任意 Node
)的连续快照,并将它们显示在您的 "live image" 区域。这是一个例子:
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
的尺寸发生变化时才创建新图像)。
另请注意,在我的示例中,我使用了很多硬编码值。您需要针对实际应用程序进行更改。
我有一个项目,其中有两个 windows,基本上您可以将它与演示模式下的 powerpoint 进行比较。在我的一个 windows 中,我想在整个第二个 window 中显示的内容的一角显示一个小预览。如果有节点的复制方法,我想我可以设法实现它,但我找不到。
为了更好地理解我尝试形象化我的问题。
您可以随时拍摄其他 Stage
的 Scene
(或任意 Node
)的连续快照,并将它们显示在您的 "live image" 区域。这是一个例子:
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
的尺寸发生变化时才创建新图像)。
另请注意,在我的示例中,我使用了很多硬编码值。您需要针对实际应用程序进行更改。