Skip to content

Instantly share code, notes, and snippets.

@chronodm
Last active December 22, 2017 04:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chronodm/3455704e38d462a8c154281b7701631b to your computer and use it in GitHub Desktop.
Save chronodm/3455704e38d462a8c154281b7701631b to your computer and use it in GitHub Desktop.
A JavaFX application that can be programmatically launched to display a given Node (for testing)
import io.reactivex.observers.DisposableObserver;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
import io.vavr.control.Option;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.util.function.Supplier;
import static io.vavr.API.None;
import static io.vavr.API.Some;
public class Preview extends Application {
// ------------------------------------------------------------
// Class fields
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private static Subject<Preview> previews = PublishSubject.create();
// ------------------------------------------------------------
// Instance fields
private final Group root;
private Option<Stage> stage = None();
// ------------------------------------------------------------
// Constructor
public Preview() {
this.root = new Group();
}
// ------------------------------------------------------------
// Application
@Override
public void start(Stage stage) {
this.stage = Some(stage);
Scene scene = new Scene(root);
stage.setScene(scene);
previews.onNext(this);
stage.show();
stage.sizeToScene();
}
// ------------------------------------------------------------
// Public methods
/**
* Launches a preview window that will display the specified node.
*
* @param node A {@code Supplier} of the node to be displayed. Guaranteed
* to be called on the JavaFX platform thread.
*/
public static void preview(Supplier<Node> node) {
previews.subscribeWith(new SetNodeObserver(node));
launch(Preview.class);
}
// ------------------------------------------------------------
// Private methods
/**
* Sets the specified node as the only child of the root group. If the
* node is a {@code Region}, also adds a listener that will resize the
* stage when the region's preferred size changes.
*
* @param node The node.
*/
private void setNode(Node node) {
root.getChildren().setAll(node);
if (node instanceof Region) {
Region region = (Region) node;
ChangeListener<Number> resizeListener = (o, v0, v1) -> stage.forEach(Stage::sizeToScene);
region.prefHeightProperty().addListener(resizeListener);
region.prefWidthProperty().addListener(resizeListener);
}
}
// ------------------------------------------------------------
// Helper classes
/**
* A one-shot observer that will call {@code setNode()} on an observed {@code Preview}
* and then {@code dispose()} itself.
*/
private static class SetNodeObserver extends DisposableObserver<Preview> {
private final Supplier<Node> node;
SetNodeObserver(Supplier<Node> node) {
this.node = node;
}
@Override
public void onNext(Preview preview) {
preview.setNode(node.get());
dispose();
}
@Override
public void onError(Throwable e) {
logger.error("Observed error", e);
dispose();
}
@Override
public void onComplete() {
// does nothing
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment