How can I set the background image of a scene?
One of the approaches may be like this:
1) Create a CSS file with name "style.css" and define an id selector in it:
#pane{
-fx-background-image: url("background_image.jpg");
-fx-background-repeat: stretch;
-fx-background-size: 900 506;
-fx-background-position: center center;
-fx-effect: dropshadow(three-pass-box, black, 30, 0.5, 0, 0);
}
2) Set the id of the most top control (or any control) in the scene with value defined in CSS and load this CSS file into the scene:
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
root.setId("pane");
Scene scene = new Scene(root, 300, 250);
scene.getStylesheets().addAll(this.getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
}
You can also give an id to the control in a FXML file:
<StackPane id="pane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="demo.Sample">
<children>
</children>
</StackPane>
For more info about JavaFX CSS Styling refer to this guide.
I know this is an old Question
But in case you want to do it programmatically or the java way
For Image Backgrounds; you can use BackgroundImage class
BackgroundImage myBI= new BackgroundImage(new Image("my url",32,32,false,true),
BackgroundRepeat.REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.DEFAULT,
BackgroundSize.DEFAULT);
//then you set to your node
myContainer.setBackground(new Background(myBI));
For Paint or Fill Backgrounds; you can use BackgroundFill class
BackgroundFill myBF = new BackgroundFill(Color.BLUEVIOLET, new CornerRadii(1),
new Insets(0.0,0.0,0.0,0.0));// or null for the padding
//then you set to your node or container or layout
myContainer.setBackground(new Background(myBF));
Keeps your java alive && your css dead..
You can change style directly for scene using .root class:
.root {
-fx-background-image: url("https://www.google.com/images/srpr/logo3w.png");
}
Add this to CSS and load it as "Uluk Biy" described in his answer.
In addition to #Elltz answer, we can use both fill and image for background:
someNode.setBackground(
new Background(
Collections.singletonList(new BackgroundFill(
Color.WHITE,
new CornerRadii(500),
new Insets(10))),
Collections.singletonList(new BackgroundImage(
new Image("image/logo.png", 100, 100, false, true),
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.CENTER,
BackgroundSize.DEFAULT))));
Use
setBackground(
new Background(
Collections.singletonList(new BackgroundFill(
Color.WHITE,
new CornerRadii(0),
new Insets(0))),
Collections.singletonList(new BackgroundImage(
new Image("file:clouds.jpg", 100, 100, false, true),
BackgroundRepeat.NO_REPEAT,
BackgroundRepeat.NO_REPEAT,
BackgroundPosition.DEFAULT,
new BackgroundSize(1.0, 1.0, true, true, false, false)
))));
(different last argument) to make the image full-window size.
Related
I have code in the form:
<BorderPane>
...
<right>
<GridPane>
...
</GridPane>
</right>
...
</BorderPane>
Obviously, now the GridPane takes a big space right of my BorderPane. What I'd like to do is add a button (or another element) that minimizes and maximizes the GridPane, so it's only fully in the view of the user when it is really needed. How can I easily achieve this?
You can do what you want by setting the Visible and Managed properties of your GridPane off and on. The centre of the BorderPane will automatically expand to take over the entire width of the BorderPane. "Managed" controls whether or not the layout manager will leave space for the node, so if you just turn Visible off, then you'll have an unused area the size of your GridPane on the right. The following code demonstrates it, I put the buttons in a VBox with a border around it so that you can see how it expands:
public class ResizeRight extends BorderPane {
public ResizeRight() {
Button openButton = new Button("Open");
Button closeButton = new Button("Close");
GridPane gridPane = new GridPane();
gridPane.addRow(0, new Text("This is just some text"));
gridPane.addRow(1, new Text("This is just some more text"));
VBox vbox = new VBox(10, openButton, closeButton);
vbox.setBorder(new Border(new BorderStroke(Color.BLACK,
BorderStrokeStyle.SOLID, CornerRadii.EMPTY, BorderWidths.DEFAULT)));
setCenter(vbox);
setRight(gridPane);
setPadding(new Insets(10));
openButton.setOnAction(evt -> {
gridPane.setVisible(true);
gridPane.setManaged(true);
});
closeButton.setOnAction(evt -> {
gridPane.setVisible(false);
gridPane.setManaged(false);
});
}
}
Run it from something like this:
public class Sample1 extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new ResizeRight(), 300, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I'm trying to make a card like the bootstrap CSS, but using JavaFX components. I want a rounded border but the background color of the top part (the header) is giving me problems.
The background overflows the border and looks quite ugly. I've googled a bit and found that an overflow:hidden on the background color should solve it. JavaFX css doesn't seem to have that though. Is there another way of solving this?
My solution so far:
As described in the JavaFX CSS Reference Guide, overflow is not supported.
JavaFX CSS does not support CSS layout properties such as float, position, overflow, and width. However, the CSS padding and margins properties are supported on some JavaFX scene graph objects. All other aspects of layout are handled programmatically in JavaFX code. In addition, CSS support for HTML-specific elements such as Tables are not supported since there is no equivalent construct in JavaFX.
However, to solve the rounded-background issue you can use -fx-background-radius along with -fx-border-radius. They should be the same value. You can find it here in the reference guide.
Here's an example of a bootstrap-like card that I think you are trying to make. You would use -fx-background-radius: <top-left> <top-right> <bottom-right> <bottom-left>; which would be -fx-background-radius: 10 10 0 0;
public class Card extends StackPane {
public BorderPane border = new BorderPane();
public StackPane header = new StackPane(), content = new StackPane();
public Card() {
setAlignment(Pos.CENTER);
getChildren().add(border);
border.setTop(header);
border.setCenter(content);
border.setStyle("-fx-border-color: cornflowerblue; -fx-border-radius: 10; ");
header.setStyle("-fx-background-color: derive(cornflowerblue, 70%); -fx-background-radius: 10 10 0 0; ");
header.setMinWidth(100);
header.setMinHeight(80);
content.setMinWidth(100);
content.setMinHeight(100);
}
public BorderPane getCard() {
return border;
}
public StackPane getHeader() {
return header;
}
public StackPane getContent() {
return content;
}
}
public void start(Stage stage) throws Exception {
Card card = new Card();
card.setPadding(new Insets(10,10,10,10));
GridPane grid = new GridPane();
grid.setVgap(10); grid.setHgap(10);
grid.setAlignment(Pos.CENTER);
grid.addRow(0, new Label("Username"), new TextField());
grid.addRow(1, new Label("Password"), new PasswordField());
grid.addRow(2, new Button("Submit"));
card.getContent().getChildren().add(grid);
Label title = new Label("Card Example");
title.setFont(Font.font("Tahoma", FontWeight.SEMI_BOLD, 36));
card.getHeader().getChildren().add(title);
StackPane stack = new StackPane();
stack.setAlignment(Pos.CENTER);
stack.getChildren().add(card);
Scene scene = new Scene(stack, 500, 300);
stage.setTitle("Boostrap-like Card Example");
stage.setScene(scene);
stage.show();
}
I made a button using scenebuilder which has two lines of text inside (first line is the function for button, and second one is a little explanation), and I would like to set different sizes for them, through css. Is this possible in any way, or is there more practical way for doing this?
Thank you for your help.
You cannot achieve this with a single text element like the one used for the button text, but you can add a Label as graphic and apply different text sizes via css:
#Override
public void start(Stage primaryStage) {
Button btn = new Button("Text");
Label explanation = new Label("This is the explanation");
explanation.getStyleClass().add("explanation");
btn.setGraphic(explanation);
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 300);
scene.getStylesheets().add(getClass().getResource("explanation.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
explanation.css
.button {
-fx-font-size: 20;
-fx-content-display: bottom;
}
.button>.explanation {
-fx-font-size: 10;
}
I'm currently developing an app. It's visual structure is the following:
Only one Stage.
Only one Scene which has an ApplicationContainer's (my own class which
is basically a StackPane with a BorderPane inside of it with a
MenuBar on top, and the current page in it's center).
Multiple ApplicationLayout's
The ApplicationLayout has a Header and a Footer (footer not implemented yet) and looks like this:
I've managed to implement fadeIn / fadeOut transitions between the pages by setting a StackPane as the BorderPane's center, adding the page to it, and on top of that, a white VBox. So before I make the page switch I work with FadeTransitions of this white VBox.
I had to do it this way because setOpacity() wouldn't change the textfields or button opacities for some reason.
Now I'm trying to do the exact same thing for the header. So I setted a StackPane to the top, and added to it the header and a on top of it a "header coverer" which supposedly should do the trick just as before (can't modify the opacity property of the title, arrow or description because of CSS overriding).
But this time it's not working, if I set the opacity of the header coverer to anything but 0, the stuff in the header doesn't show.
What I want to acomplish is to fadeOut / FadeIn the components of the header but not the orange HBox.
EDIT: Added a minimal example where this doesn't work for me
public class Main extends Application {
private Boolean buttonPressed = false;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
BorderPane appWindow = new BorderPane();
appWindow.setStyle("-fx-alignment: center; -fx-padding: 30 0 0 30");
appWindow.setBackground(new Background(new BackgroundFill(Color.PERU, null, null)));
GridPane loginContainer = new GridPane();
appWindow.setCenter(loginContainer);
TextField username = new TextField();
PasswordField password = new PasswordField();
Label userNameDesc = new Label("Username");
Label passwordDesc = new Label("Password");
Button logInBtn = new Button("Log In");
logInBtn.setTranslateX(100);
logInBtn.setTranslateY(20);
logInBtn.setOnAction(event -> {
if (!buttonPressed) {
appWindow.getCenter().setOpacity(30);
buttonPressed = true;
System.out.println("Opacity set to " + appWindow.getCenter().getOpacity());
}
else {
appWindow.getCenter().setOpacity(100);
buttonPressed = false;
System.out.println("Opacity set to " + appWindow.getCenter().getOpacity());
}
});
loginContainer.addColumn(0, userNameDesc, passwordDesc);
loginContainer.addColumn(1, username, password);
loginContainer.add(logInBtn, 1, 2);
Scene scene = new Scene(appWindow, 300, 250);
stage.setScene(scene);
stage.show();
}
}
Pressing the "Log In" button should affect the Gridpane and Gridpane childs visual opacity, but it doesn't. It just prints the correct opacity values.
According to the documentation:
Opacity is specified as a value between 0 and 1. Values less than 0 are treated as 0, values greater than 1 are treated as 1.
So setting the value to 30 or to 100 has no effect: both are treated as fully opaque (i.e. they are clamped at 1).
Replacing
appWindow.getCenter().setOpacity(30);
with
appWindow.getCenter().setOpacity(0.3);
will make the center content partially transparent.
I'd like to create a grid as a background for my JavaFX application. My current solution is to paint a rectangle on a canvas, create an image pattern from it and set it as fill.
Question: Is there a better way to approach this, preferrably via CSS?
Current version:
public class BackgroundGrid extends Application {
double gridSize = 20;
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(new Group(), 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
scene.setFill(createGridPattern());
}
public ImagePattern createGridPattern() {
double w = gridSize;
double h = gridSize;
Canvas canvas = new Canvas(w, h);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setStroke(Color.BLACK);
gc.setFill(Color.LIGHTGRAY.deriveColor(1, 1, 1, 0.2));
gc.fillRect(0, 0, w, h);
gc.strokeRect(0, 0, w, h);
Image image = canvas.snapshot(new SnapshotParameters(), null);
ImagePattern pattern = new ImagePattern(image, 0, 0, w, h, false);
return pattern;
}
public static void main(String[] args) {
launch(args);
}
}
Thank you very much!
Edit: in order to get sharp grid lines, just use
gc.strokeRect(0.5, 0.5, w, h);
I think that wouldn't be doable in CSS, isn't it?
You can do it with CSS too. This is all you need:
.root {
-fx-background-color: #D3D3D333,
linear-gradient(from 0.5px 0.0px to 10.5px 0.0px, repeat, black 5%, transparent 5%),
linear-gradient(from 0.0px 0.5px to 0.0px 10.5px, repeat, black 5%, transparent 5%);
}
The 0.5px offset solves some buggy behavior when set from 0px to 10px, and some lines are rendered with two pixels instead of one:
Here is an answer reproduced from an old Oracle forum post.
GridPane based approach
A few methods (base upon a GridPane layout):
style borders of the individual cells (and ensure that they fill
their entire grid position) OR
style the background of the whole
grid leaving gaps between cells which fill their entire grid
position as is shown below OR
add new grid nodes with lines and then
style the added lines.
I chose method 2 (styling the grid background) for the code below. The sample uses inline CSS styles (cause I'm lazy), but it would work (and be better) with an external CSS stylesheet to style the grid.
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class GridPaneStyle extends Application {
#Override
public void start(final Stage stage) {
// create a grid with some sample data.
GridPane grid = new GridPane();
grid.addRow(0, new Label("1"), new Label("2"), new Label("3"));
grid.addRow(1, new Label("A"), new Label("B"), new Label("C"));
// make all of the Controls and Panes inside the grid fill their grid cell,
// align them in the center and give them a filled background.
// you could also place each of them in their own centered StackPane with
// a styled background to achieve the same effect.
for (Node n : grid.getChildren()) {
if (n instanceof Control) {
Control control = (Control) n;
control.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
control.setStyle("-fx-background-color: cornsilk; -fx-alignment: center;");
}
if (n instanceof Pane) {
Pane pane = (Pane) n;
pane.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
pane.setStyle("-fx-background-color: cornsilk; -fx-alignment: center;");
}
}
// style the grid so that it has a background and gaps around the grid and between the
// grid cells so that the background will show through as grid lines.
grid.setStyle("-fx-background-color: palegreen; -fx-padding: 2; -fx-hgap: 2; -fx-vgap: 2;");
// turn layout pixel snapping off on the grid so that grid lines will be an even width.
grid.setSnapToPixel(false);
// set some constraints so that the grid will fill the available area.
ColumnConstraints oneThird = new ColumnConstraints();
oneThird.setPercentWidth(100 / 3.0);
oneThird.setHalignment(HPos.CENTER);
grid.getColumnConstraints().addAll(oneThird, oneThird, oneThird);
RowConstraints oneHalf = new RowConstraints();
oneHalf.setPercentHeight(100 / 2.0);
oneHalf.setValignment(VPos.CENTER);
grid.getRowConstraints().addAll(oneHalf, oneHalf);
// layout the scene in a stackpane with some padding so that the grid is centered
// and it is easy to see the outer grid lines.
StackPane layout = new StackPane();
layout.setStyle("-fx-background-color: whitesmoke; -fx-padding: 10;");
layout.getChildren().addAll(grid);
stage.setScene(new Scene(layout, 600, 400));
stage.show();
// can be uncommented to show the grid lines for debugging purposes, but not particularly useful for styling purposes.
//grid.setGridLinesVisible(true);
}
public static void main(String[] args) {
launch();
}
}
Alternate Canvas Based Approach
See also the FXExperience blog post Resizable Grid using Canvas.
The advice to get really sharp grid lines is not correct for all systems. On a Retina display you would have to use a line width of 0.5 and then an offset of 0.25 from the integer line coordinates. So in practice you would have to determine on what system your application is running and then use different line widths and offsets.