Last active
December 22, 2017 04:08
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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