How to draw a gradient over the scene on JavaFX? - java

Is there a way to draw a radial gradient from black to transparent over the entire scene of a JavaFX stage?
I want to achieve something like this:

Here is a quick answer which uses a StackPane as the scene root to allow addition of an overlay with a radial gradient background varying from black to transparent.
You can adjust the radial gradient colors or radius, e.g. make the inner color Color.BLACK.deriveColor(0, 1, 1, 0.2), to change the amount of highlight and intensity in the effect.
Gradients such as this can be set in CSS as well, so you could use CSS rather than Java code to style the effect if you wished.
The output of this implementation suffers a little bit from banding of the radial gradient (not sure how to improve that further), but it's kind of OK depending on your tolerance.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.effect.BoxBlur;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.stage.Stage;
// java 8
// click on the scene to place a shaded lens effect over the scene.
public class ShadedScene extends Application {
#Override
public void start(Stage stage) {
StackPane layout = new StackPane(
new Label("Click to shade/unshade")
);
layout.setPrefSize(400, 300);
Scene scene = new Scene(layout);
makeShadeable(scene);
stage.setScene(scene);
stage.show();
}
/**
* Applies a lens effect gradient to a scene root node.
* The effect is kind of like a flashlight shining against the wall in the dark.
*
* For the gradient to be applied, the scene's root must be defined and a Pane
* to which the effect can added and removed as a child.
*
* #param scene the scene to have the effect applied.
*/
private void makeShadeable(Scene scene) {
if (scene.getRoot() == null ||
!(scene.getRoot() instanceof Pane)) {
return;
}
Pane shade = new Pane();
RadialGradient shadePaint = new RadialGradient(
0, 0, 0.5, 0.5, 1, true, CycleMethod.NO_CYCLE,
new Stop(1, Color.BLACK),
new Stop(0, Color.TRANSPARENT)
);
shade.setBackground(
new Background(
new BackgroundFill(
shadePaint, null, new Insets(-10)
)
)
);
// blur helps reduce visible banding of the radial gradient.
shade.setEffect(new BoxBlur(5, 5, 3));
Pane root = (Pane) scene.getRoot();
scene.setOnMouseClicked(event -> {
if (root.getChildren().contains(shade)) {
root.getChildren().remove(shade);
} else {
root.getChildren().add(shade);
}
});
}
public static void main(String[] args) {
launch(args);
}
}
There are other ways to accomplish something similar to the desired effect. For example the technique below applies an inner shadow and color adjustment to the root pane directly, so it requires no additional nodes.
private void makeShadeableByInnerShadow(Scene scene) {
InnerShadow shade = new InnerShadow();
shade.setWidth(120);
shade.setHeight(120);
shade.setInput(new ColorAdjust(0, 0, -0.3, 0));
Parent root = scene.getRoot();
scene.setOnMouseClicked(event -> {
if (root.getEffect() == null) {
root.setEffect(shade);
} else {
root.setEffect(null);
}
});
}

Considering your example, you could post this on http://pt.stackoverflow.com. as most of your interface is in Brazilian Portuguese.
The answer is exactly what jewelsea posted. But as I was also answering when I got notified that there was an answer, I posted mine as well.
Test.java
package br;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Test extends Application {
public static Stage thisStage;
#Override
public void start(Stage stage) throws Exception {
thisStage = stage;
Parent root = FXMLLoader.load(getClass().getResource("doc.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
stage.setScene(scene);
stage.setTitle("Happy Client - Overlay");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
TestController.java
package br;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
public class TestController implements Initializable{
#FXML Pane mainPane;
#FXML Pane overlayPane;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
overlayPane.getStyleClass().add("grad");
overlayPane.toFront();
overlayPane.addEventHandler(MouseEvent.MOUSE_PRESSED,
new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent arg0) {
overlayPane.toBack();
}
});
}
}
doc.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.shape.*?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="br.TestController">
<children>
<Pane fx:id="mainPane" prefHeight="98.0" prefWidth="600.0">
<children>
<TableView layoutX="-2.0" layoutY="99.0" prefHeight="300.0" prefWidth="600.0">
<columns>
<TableColumn prefWidth="75.0" text="Nome" />
<TableColumn prefWidth="75.0" text="RG" />
<TableColumn prefWidth="75.0" text="CPF" />
<TableColumn prefWidth="75.0" text="Idade" />
</columns>
</TableView>
<Label layoutX="162.0" layoutY="41.0" style="-fx-font-size: 32;" text="Informe o cliente" />
<Line endX="500.0" layoutX="100.0" layoutY="98.0" startX="-100.0" />
</children>
</Pane>
<Pane fx:id="overlayPane" opacity="0.8" prefHeight="200.0" prefWidth="200.0" />
</children>
</StackPane>
style.css
.grad{
-fx-padding: 40;
-fx-background-color: radial-gradient(center 50% 50%, radius 140%, rgba(200,200,200,70) 5%,rgba(0,0,0,100) 35%);
}
Note that you will have to use a StackPane and not other such as AnchorPane because if you set the style directly on an AnchorPane the style would not work for your elements above it such as your table, as you may see below:

Related

JavaFx zooming and panning an image with overlaid fixed scale labels

I am a doctor at a University and I am developing X-ray analysis software in which a user defines anatomical points with small circles by placing them on an X-ray image. I'm satisfied so far, but I need to implement zooming and panning using a mouse wheel, according to the mouse position.
I simplified my code to be clear, the original one is way complicated than that.
In this algorithm, points should NOT move according to the image while zooming and panning so their position is maintained and the Label near the point has to stay in the same font size while zooming (we don't want to see gigantic Label). I am stuck at this point.
Please help can you just generate this algorithm?
Here is the sample:
Here is my java code:
package main.java;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Circle;
public class ZoomClass {
#FXML
AnchorPane xRayAnchorPane;
#FXML
ImageView xRayImage;
#FXML
ScrollPane xRayScrollPane;
#FXML
Label pointsLabel;
public void initialize() {
xRayImage.setOnMouseClicked(mouseEvent ->
{
if(mouseEvent.getButton().equals(MouseButton.PRIMARY)) // ADD POINTS
{
Circle circle = new Circle();
circle.setCenterX(mouseEvent.getX()+58); // Some Offset values to proper positioning
circle.setCenterY(mouseEvent.getY()+75); // Some Offset values to proper positioning
circle.setRadius(2);
xRayAnchorPane.getChildren().add(circle); // Adding circle to mainFrame
pointsLabel.setText("A"); // Defining the point's name
pointsLabel.setLayoutX(circle.getCenterX()+5); // Some Offset values to proper positioning
pointsLabel.setLayoutY(circle.getCenterY()); // Some Offset values to proper positioning
}
});
}
}
And my FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="650.0" prefWidth="851.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="main.java.ZoomClass" fx:id="xRayAnchorPane">
<children>
<ScrollPane layoutX="56.0" layoutY="71.0" prefHeight="533.0" prefWidth="743.0" fx:id="xRayScrollPane">
<content>
<ImageView fitHeight="736.0" fitWidth="739.0" pickOnBounds="true" preserveRatio="true" fx:id="xRayImage">
<image>
<Image url="#ceph2.jpg" />
</image>
</ImageView>
</content>
</ScrollPane>
<Label fx:id="pointsLabel" layoutX="14.0" layoutY="138.0" />
</children>
</AnchorPane>
According to this question, you need to create a group element for the elements you want to zoom in. When you create new circles, you should add to zoom group. Finally, apply zoom on the group element you created
Does this help?
The scale factor is set only on the ImageView by using the mouse wheel with CTRL held down.
The labels are placed in the AnchorPane outside of the ScrollPane, so they are not effected by the pan and zoom as you require.
package com.stackoverflow.zoom;
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.input.ZoomEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Zoomer extends Application {
private AnchorPane ap;
private ImageView imgView;
private char markTxt = 'A';
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
ap = new AnchorPane();
Image img = new Image("https://upload.wikimedia.org/wikipedia/commons/d/dc/Medical_X-Ray_imaging_SEQ07_nevit.jpg");
imgView = new ImageView(img);
ScrollPane sp = new ScrollPane(imgView);
AnchorPane.setTopAnchor(sp, 0.0);
AnchorPane.setLeftAnchor(sp, 0.0);
AnchorPane.setBottomAnchor(sp, 0.0);
AnchorPane.setRightAnchor(sp, 0.0);
ap.getChildren().add(sp);
imgView.setOnMouseClicked(this::onClick);
imgView.setOnScroll(this::imageScrolled);
Scene scene = new Scene(ap);
primaryStage.setTitle("Zoom Image");
primaryStage.setScene(scene);
primaryStage.show();
}
public void onClick(MouseEvent event) {
if (event.getButton() == MouseButton.PRIMARY) {
placeMarker(event.getSceneX(), event.getSceneY());
}
}
private void imageScrolled(ScrollEvent event) {
// When holding CTRL mouse wheel will be used for zooming
if (event.isControlDown()) {
double delta = event.getDeltaY();
double adjust = delta / 1000.0;
double zoom = Math.min(10, Math.max(0.1, imgView.getScaleX() + adjust));
setImageZoom(zoom);
event.consume();
}
}
private void placeMarker(double sceneX, double sceneY) {
Circle circle = new Circle(2);
circle.setStroke(Color.RED);
circle.setTranslateY(-12);
Label marker = new Label(String.valueOf(markTxt), circle);
marker.setTextFill(Color.RED);
markTxt++;
Point2D p = ap.sceneToLocal(sceneX, sceneY);
AnchorPane.setTopAnchor(marker, p.getY());
AnchorPane.setLeftAnchor(marker, p.getX());
ap.getChildren().add(marker);
}
private void setImageZoom(double factor) {
imgView.setScaleX(factor);
imgView.setScaleY(factor);
}
}

how to combine fxml file with 3d Box and PerspectiveCamera

As a newbie I'm trying to do some my own projects to practice Java, JavaFX and Raspberry coding. Ma latest goal which I set for myself is 3D visualization of force from tensometric beam. I managed to achieve simple chart and and simple visualization of actual pressure force (in circle).
(https://imagizer.imageshack.com/img922/2663/spBwMs.gif)
Now I'd like to represent it as 3D bar.
I tried to understood some examples from Ensemble: jnlps://download.oracle.com/otndocs/products/javafx/8/samples/Ensemble/Ensemble.jnlp
and I managed to do something like that:
(https://imagizer.imageshack.com/img921/2766/12te0a.gif)
but I'd like to achieve something similar using FXML file.
I tried to code it but no effect so far. I'd like you use some Hbox to place 2 boxes next to each other, but then I don't know where to place Camera properly. Actually 3D with javaFX is a little bit of black magic for me ;)
Main.java:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root,800,800, true, SceneAntialiasing.BALANCED));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller.java:
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.fxml.FXML;
import javafx.scene.*;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.util.Duration;
public class Controller{
#FXML
private AnchorPane pane;
#FXML
private Box box;
#FXML
private PerspectiveCamera camera;
final Rotate rx = new Rotate(0, Rotate.X_AXIS);
final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
final Rotate rz = new Rotate(0, Rotate.Z_AXIS);
private Timeline animation;
#FXML
void initialize() {
box.setMaterial(new PhongMaterial(Color.ORANGE));
/* box.setDepth(100);
box.setWidth(100);
box.setHeight(100);*/
rx.setAngle(90);
ry.setAngle(25);
box.getTransforms().addAll(rz, ry, rx);
animation = new Timeline();
animation.getKeyFrames().addAll(
new KeyFrame(Duration.ZERO,
new KeyValue(box.depthProperty(), 0d),
new KeyValue(box.translateYProperty(),400d)),
new KeyFrame(Duration.seconds(5),
new KeyValue(box.depthProperty(), 800d),
new KeyValue(box.translateYProperty(), 0d)));
animation.setCycleCount(Timeline.INDEFINITE);
camera.getTransforms().addAll (
new Rotate(-35, Rotate.X_AXIS),
new Translate(0, 0, 10)
);
box.sceneProperty().addListener(new InvalidationListener() {
#Override
public void invalidated(Observable observable) {
box.getScene().setCamera(camera);
box.sceneProperty().removeListener(this);
}
});
animation.play();
}
}
main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.PerspectiveCamera?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Box?>
<AnchorPane fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="check.brakes.Controller">
<children>
<Box fx:id="box" depth="100.0" height="100.0" layoutX="380.0" layoutY="673.0" width="100.0">
</Box>
<PerspectiveCamera fx:id="camera" farClip="70.0" fieldOfView="35.0" nearClip="0.5" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
I expect the bars should look like from the example I provided.
Update
I did it, I'm sure it's not perfect at all, but somehow I have to start.
BTW.
Why is that, when i resize application window, camera angle is changing ?

Trouble applying CSS to programatically created Pane on MouseEvent

I have a stack pane that when the mouse enters, I create a pane, stick some text in it, and display it near the mouse.
StatisticsController.java
stackPane.setOnMouseEntered(event -> {
Pane pane = new Pane();
Text text = new Text("Example Text");
//Add the text to the pane and set it near the mouse
pane.getChildren().add(text);
pane.setLayoutY(event.getSceneY() - 50);
pane.setLayoutX(event.getSceneX() - 100);
//add the style class to give it a blueBG background
pane.getStyleClass().add("blueBG");
// add it too our root
getRoot().getChildren().add(pane);
});
As you can see below when the Pane and text appear when I roll over the stackPane (the black circle and question mark in the image).
However it doesn't have the blue background I'm looking for.
What I find strange is if instead of adding it to the root and I add it to an existing Vbox, it styles correctly (Here I roll over the same stackPane):
So:
//Styles Correctly
getInfoBox().getChildren().add(pane);
// Adds but does not style
getRoot().getChildren().add(pane);
Some things that may be worth noting:
1)getInfoBox() is a static getter. I have multiple controllers which extend a MasterController which has static instance variables to things all controllers would want to be able to access - like the infoBox, to display information.
2)The root is a BorderPane made in the Main class:
Main.java
//Create the root
BorderPane root = new BorderPane();
// I've cut it out to save space but this repeats 4 times to set
//an .fxml file for the top, left, right and bottom of the borderPane ///
FXMLLoader headerLoader = new FXMLLoader(getClass().getResource("/view/header.fxml"));
Parent headerRoot = headerLoader.load();
root.setTop(headerRoot);
//------------------------------------------//
//Set the static reference in the MasterController
MasterController.setRoot(root);
Scene scene = new Scene(root,1366,768);
primaryStage.setScene(scene);
primaryStage.show();
3) The css files are all declared in the .fxml files using Scene Builder. The top, bottom, left, right .fxml files all have the same css (main.css). So does the statistic.fxml which is loaded on button click into the center (you can see in the image)
Suggestion: Could it be because the CSS is not defined for the Scene or BorderPane itself, it only applies to nodes added into the borderPane sections? If so how would I go about letting the enter Scene/Stage use the same css and would that negate adding in the css to each .fxml?
Edit:
When adding this code to the main to apply the CSS to the scene:
Scene scene = new Scene(root,1366,768);
scene.getStylesheets().add(getClass().getResource("/css/main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
I get this:
So the CSS for the text is now working, but not for the Pane? I have no idea why this might happen.
// ---- REPRODUCTION -- //
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
BorderPane bp = new BorderPane();
MasterController.setRoot(bp);
Parent left = FXMLLoader.load(getClass().getResource("left.fxml"));
Parent right = FXMLLoader.load(getClass().getResource("right.fxml"));
bp.setLeft(left);
bp.setRight(right);
Scene scene = new Scene(bp, 600, 400);
scene.getStylesheets().add(getClass().getResource("main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MasterController.java
package sample;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
public class MasterController {
private static VBox rightBox;
private static BorderPane root;
public static VBox getRightBox() {
return rightBox;
}
public static void setRightBox(VBox rightBox) {
MasterController.rightBox = rightBox;
}
public static BorderPane getRoot() {
return root;
}
public static void setRoot(BorderPane root) {
MasterController.root = root;
}
}
LeftController.java
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import java.io.IOException;
public class LeftController extends MasterController {
#FXML
public void loadCenter(ActionEvent event) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("center.fxml"));
Parent center = loader.load();
getRoot().setCenter(center);
} catch (IOException e){
e.printStackTrace();
}
}
}
CenterController.java
package sample;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
public class CenterController extends MasterController {
#FXML
private VBox center;
public void initialize() {
Platform.runLater(this::build);
}
public void build() {
center.getChildren().add(new Text("loaded"));
StackPane stackPane = new StackPane();
Text text = new Text("ROLL OVER");
stackPane.getChildren().add(text);
center.getChildren().add(stackPane);
stackPane.setOnMouseEntered(event -> {
getRightBox().getChildren().clear();
Pane pane1 = new Pane();
Text exampleText1 = new Text("Example Text");
pane1.getStyleClass().add("blueBG");
Pane pane2 = new Pane();
Text exampleText2 = new Text("Example Text");
pane2.getStyleClass().add("blueBG");
pane1.getChildren().add(exampleText1);
pane2.getChildren().add(exampleText2);
pane1.setLayoutY(event.getSceneY() + 40);
pane1.setLayoutX(event.getSceneX() - 40);
getRoot().getChildren().add(pane1);
getRightBox().getChildren().add(pane2);
});
}
}
RightController.java
package sample;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
public class RightController extends MasterController {
#FXML
private VBox rightBox;
public void initialize() {
setRightBox(rightBox);
}
}
left.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LeftController">
<children>
<Button mnemonicParsing="false" onAction="#loadCenter" prefHeight="38.0" prefWidth="200.0" text="Click me to load center" />
</children>
</VBox>
center.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="center" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="#main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.CenterController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Center" />
</children>
</VBox>
right.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="rightBox" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="#main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.RightController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Right Box" />
</children>
</VBox>
main.css
.blueBG {
-fx-background-color: aqua;
}
You should get the following result. You can see the pane is being styled correctly when added to the right, but not when added too the root.
BorderPane only applies layout to the center, left, right, top and bottom children. It's however the parent of a layout (or the scene in case of a root) that sets the size of a Region during a layout pass (or not, like in this case).
The result is that the style is applied to the Pane, but the size of the Pane remains 0. You can verify this by adding
pane1.resize(100, 100);
to the event handler to set the size of the pane.
You need to use a different kind of layout as parent for pane1's size to become non-empty or resize it yourself.

How to maintain full screen when changing scenes javafx

I have seen a similar question being asked, however my problem is that I want the stage to maintain full screen mode during the entirety of the scene change ie not simply adding stage.setFullScreen(true) at the end of it, which causes a momentary but very noticeable exit from full screen. Hiding the stage before changing scenes doesn't really help either, as there is a noticeable disappearance . Here's my code:
Main:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root));
primaryStage.setFullScreen(true);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller:
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class Controller {
#FXML
private AnchorPane pane;
#FXML
void doSomething(ActionEvent event) throws Exception {
Stage stage = (Stage) pane.getScene().getWindow();
Parent parent = FXMLLoader.load(getClass().getResource("sample2.fxml"));
Scene scene = new Scene(parent);
stage.setScene(scene);
stage.setFullScreen(true);
stage.show();
}
}
Sample:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-
Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"
xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.Controller">
<children>
<Button layoutX="180.0" layoutY="188.0" mnemonicParsing="false"
onAction="#doSomething" prefHeight="25.0" prefWidth="241.0" text="Do Something"
/>
</children>
</AnchorPane>
Sample2
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane fx:id="pane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-
Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" style="-fx-background-color: blue;"
xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.Controller">
<children>
<Button layoutX="180.0" layoutY="188.0" mnemonicParsing="false"
onAction="#doSomething" prefHeight="25.0" prefWidth="241.0" text="Do Something"
/>
</children>
</AnchorPane>
As you can see, if you run the code and press the button, there is a momentary exit from full screen. Is there any way to fix this, other than using the same fxml file?
Thanks a lot.
I didn't clearly understood what you are saying. I think you need a stage of size equals to Computer screen resolution and switch between the two screens. If yes then the following files will help you do so. If you want to come back to first scene from second scene then keep another button to load the first scene or keep a static variable and switch between the scenes by incrementing the variable and show the scene based on odd or even. Like for odd value of the variable show first scene and for even values show second scene.
Other process is getting the children of the stage. This gives you a ObservableList. Now clear the list and then add the respective scene to the list and show the stage.
Main class:
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
Scene scene = new Scene(root, 500, 200);
primaryStage.setScene(scene);
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
//set Stage boundaries to visible bounds of the main screen
primaryStage.setX(primaryScreenBounds.getMinX());
primaryStage.setY(primaryScreenBounds.getMinY());
primaryStage.setWidth(primaryScreenBounds.getWidth());
primaryStage.setHeight(primaryScreenBounds.getHeight());
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller Class:
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Controller {
#FXML
private AnchorPane pane;
#FXML
void doSomething(ActionEvent event) throws Exception {
Stage stage = (Stage) pane.getScene().getWindow();
Parent parent = FXMLLoader.load(getClass().getResource("sample2.fxml"));
Scene scene = new Scene(parent, 500, 200);
stage.setScene(scene);
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
//set Stage boundaries to visible bounds of the main screen
stage.setX(primaryScreenBounds.getMinX());
stage.setY(primaryScreenBounds.getMinY());
stage.setWidth(primaryScreenBounds.getWidth());
stage.setHeight(primaryScreenBounds.getHeight());
stage.show();
}
}

How do you add nodes to an object that is not the main parent (javafx)?

I could not find anything on the topic anywhere i looked. I would like to add a rectangle to my AnchorPane (anchorPaneOne) that is inside my ScrollPane (scrollPane) but whatever i see to do i keep getting errors.
Here is my code:
Main Class:
package application;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
public class Main extends Application {
#FXML
ScrollPane scrollPane;
#FXML
AnchorPane main;
#FXML
AnchorPane anchorPaneOne;
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene(root,600,400);
primaryStage.setScene(scene);
primaryStage.setTitle("Stack Overflow Example");
primaryStage.show();
Rectangle r = new Rectangle();
//It will not let me do anchorPaneOne.getChildren().add(r);
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<AnchorPane fx:id="main" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<children>
<ScrollPane fx:id="scrollPane" prefHeight="400.0" prefWidth="600.0">
<content>
<AnchorPane fx:id="anchorPaneOne" minHeight="0.0" minWidth="0.0" prefHeight="800.0" prefWidth="585.0" />
</content>
</ScrollPane>
</children>
</AnchorPane>
Any assistance would be appreciated.
Thanks
The loader needs to know where to inject the instances to - without the field anchorPaneOne can't be instantiated and remains null. That's done by the controller property which must be set before actually loading the ui:
// create a loader
FXMLLoader loader = new FXMLLoader(getClass().getResource(resource));
// set this instance as its controller
loader.setController(this);
// load the ui
Parent root = loader.load();
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.setTitle("Stack Overflow Example");
primaryStage.show();
Rectangle r = new Rectangle(100, 100);
// now the field is instantiated and can be accessed without NPE
anchorPaneOne.getChildren().add(r);

Categories