I've created a very simple CSS that styles two buttons.
To the first has just been added a padding.
To the second has been set the -fx-background-color, but the value is taken from caspian.css, that is the value it should have before it had been set.
.first-style { -fx-padding: 20 5 1 5; }
.second-style { -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; }
At this point i experience a strange behavior: the focus decoration stops working, and the second button doesn't get its blue border when focused.
What's happening?
You need to add a :focused psuedo-class to the second style to allow the focus ring to work otherwise you just overwrite it when you respecify the background color of the button in the second-style style class.
Sample CSS:
.root { -fx-background-color: cornsilk; -fx-padding: 10; }
.first-style { -fx-padding: 20 5 1 5; }
.second-style { -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color; }
.second-style:focused { -fx-background-color: -fx-focus-color, -fx-outer-border, -fx-inner-border, -fx-body-color; }
Sample app:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class ButtonFocusCss extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws Exception {
VBox layout = new VBox(15);
Button b1 = new Button("B1");
b1.getStyleClass().add("first-style");
Button b2 = new Button("B2");
b2.getStyleClass().add("second-style");
layout.getChildren().addAll(b1, b2);
layout.getStylesheets().add(getClass().getResource("button.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
}
Update
Honestly I can't explain exactly why the JavaFX CSS override mechanism works this way, I got the answer here by reviewing the default JavaFX 2.2 caspian.css and following a hunch on how it might work.
The best current explanation of the rules of application for JavaFX CSS is in the CSS Reference Guide section CSS and the JavaFX Scene Graph, though there are subtleties in this example for which you need to turn to a general CSS specification to understand things such as cascading order and specifity.
Related
I am using an JavaFX Alert with a text area on it.
The problem I have is that the text area does not use the full space of the Alert, as well as having white (borders).
My code:
TextArea area = new TextArea("");
area.setWrapText(true);
area.setEditable(false);
area.getStylesheets().add(getClass().getResource("/model/app.css").toExternalForm());
Alert alert = new Alert(AlertType.NONE);
alert.getDialogPane().setPrefWidth(750);
alert.getDialogPane().setPrefHeight(800);
alert.getDialogPane().setContent(area);
formatDialog(alert.getDialogPane());
alert.setTitle("Lizenz Info");
Window w = alert.getDialogPane().getScene().getWindow();
w.setOnCloseRequest(e -> {
alert.hide();
});
w.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.ESCAPE) {
w.hide();
}
}
});
alert.setResizable(true);
alert.showAndWait();
My corresponding css sheet:
.text-area .content {
-fx-background-color: #4c4c4c;
}
.text-area {
-fx-text-fill: #ff8800;
-fx-font-size: 15.0px;
}
.text-area .scroll-pane {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .viewport {
-fx-background-color: #4c4c4c;
}
.text-area .scroll-pane .content {
-fx-background-color: #4c4c4c;
}
.viewport and .content on .scrollpane did not have any effect whatsoever.
I want the white borders either to be gone, or have the same color as the background, also to use the full space of the dialog. Can someone help?
As #jewelsea suggested, I think Alert is not the right choice here. Your desired layout can be acheived by using Dialog (as in below code).
Dialog<String> dialog = new Dialog<>();
dialog.setTitle("Lizenz Info");
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK);
dialog.getDialogPane().setContent(area);
dialog.setResizable(true);
dialog.showAndWait();
Having said that, you can fix the existing issues as below:
Remove white space around text area: You can remove the white space by setting the padding of TextArea to 0. Include the below code in the css file.
.text-area{
-fx-padding:0px;
}
Changing the white space background : The .text-area and .content styleclasses are on same node. So instead of declaring with space between them
.text-area .content {
-fx-background-color: #4c4c4c;
}
you have to declare without the space between the styleclasses (in below code)
.text-area.content {
-fx-background-color: #4c4c4c;
}
Here is a similar example to Sai's but uses a standard stage.
It uses a UTILITY style, but you could use a different style if you prefer.
Basically, if you don't want the additional styling and functionality of the alerts and dialogs (and you don't seem to with at least the example you have given), then you can just use a standard stage to display your content rather than the dialog classes provided in the javafx.control package.
The alert.css file referenced in the example is the CSS from your question.
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.input.*;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class TextAreaUtility extends Application {
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) {
Button showAlert = new Button("Show Alert");
showAlert.setOnAction(this::showAlert);
stage.setScene(new Scene(showAlert));
stage.show();
}
private void showAlert(ActionEvent e) {
TextArea textArea = new TextArea("");
textArea.setWrapText(true);
textArea.setEditable(false);
Scene scene = new Scene(textArea, 750, 800);
scene.getStylesheets().add(
TextAreaUtility.class.getResource(
"alert.css"
).toExternalForm()
);
Stage utility = new Stage(StageStyle.UTILITY);
utility.initOwner(((Button) e.getSource()).getScene().getWindow());
utility.initModality(Modality.APPLICATION_MODAL);
utility.setTitle("Alert Title");
utility.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if (event.getCode() == KeyCode.ESCAPE) {
utility.hide();
}
});
utility.setResizable(true);
utility.setScene(scene);
utility.showAndWait();
}
}
Debugging nodes and styles info
If you want to see the nodes and style names in your scene graph and you aren't using a tool like ScenicView, a quick debug function is:
private void logChildren(Node n, int lvl) {
for (int i = 0; i < lvl; i++) {
System.out.print(" ");
}
System.out.println(n + ", " + n.getLayoutBounds());
if (n instanceof Parent) {
for (Node c: ((Parent) n).getChildrenUnmodifiable()) {
logChildren(c, lvl+1);
}
}
}
Which you can attach to run when the window is displayed:
w.setOnShown(se -> logChildren(alert.getDialogPane().getScene().getRoot(), 0));
When you run this on a standard dialog you will see quite a few nodes in the scene graph with attached styles that you can find defined in the modena.css file within the JavaFX SDK. You will also see that some of the bounding boxes for the layout that are not related to your text area have width and height.
Those dialog styles by default have padding attached to them, which is why you are seeing padding around your TextArea. The padding is not in the text area but the content regions containing it within the dialog. To get rid of it, you need to set the padding in your custom CSS to override the default. I don't have the CSS for that, it is difficult to create sometimes and overriding default padding is probably best avoided when possible.
I want to have transparent progressindicator, which is indefinite.
here is the code, it shows grey background state/scene.
i wanted fully transparent.
I tried following code, but it shows background stage which is not transparent.
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class Main extends Application {
#Override
public void start(Stage stage) {
/*
*
* my css file content:
*
* .progress-indicator .indicator { -fx-background-color: transparent;
* -fx-background-insets: 0; -fx-background-radius: 0;
*
* } .progress-indicator { -fx-progress-color: green ; }
*
*
*
*/
Stage initStage = new Stage();
initStage.initStyle(StageStyle.TRANSPARENT);
ProgressIndicator loadProgress = new ProgressIndicator();
loadProgress.setSkin(null);
loadProgress.setPrefWidth(50);
VBox box = new VBox();
box.getChildren().add(loadProgress);
final Scene scene = new Scene(box, 150, 150);
scene.setFill(Color.TRANSPARENT);
initStage.setScene(scene);
scene.getStylesheets().add("application.css");
initStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
For modena.css (the default JavaFX look and feel definition in Java 8), a slight shaded background was introduced for all controls (and also to panes if a control is loaded).
You can remove this by specifying that the default background is transparent. This can be done by adding the following line to your application's CSS file:
.root { -fx-background-color: transparent; }
This is in addition to other settings you already have in your code to initialize the style of the stage and background fill of the scene.
stage.initStyle(StageStyle.TRANSPARENT);
scene.setFill(Color.TRANSPARENT);
Note: in the questions's sample code, an additional stage (initStage) is created instead of using the passed in stage for the start method. The passed in stage can be initialized, utilized and shown directly by your code rather than creating an additional initStage.
stage.initStyle(StageStyle.TRANSPARENT);
this is for hide the top bar ( minimize, Restore Down and close)
scene.setFill(Color.TRANSPARENT);
this is for the frame color ( you can replace TRANSPARENT with any color GREEN YELLOW RED BLUE ...) but for me I want glass view if you can understand me, and with different color so the solution is
primaryStage.setOpacity(0.2);
The number 0.2 is between 0 and 1. 0 is hidden and 1 is normal form but between the numbers transparent so choose your number and run your program and see if this is what you want there is this code for full screen.
primaryStage.setFullScreen(true);
and in the css file do this
.root { -fx-background-color:rgba(0,0,0,1); }
and you can change the color with changed the number in rgba(0,0,0,1)
This works for me.
Parent root = FXMLLoader.load(getClass().getResource("login.fxml"));
Scene scene = new Scene(root);
scene.setFill(Color.TRANSPARENT);
stage.setScene(scene);
stage.initStyle(StageStyle.TRANSPARENT);
stage.show();
U just need mainly 2 things:
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
https://stackoverflow.com/a/10615258/529411
I would like to add a background color to my tabpane dynamically (depending on certain conditions). How can I achieve this from code? One option is to assign he tab a specific ID which has the associated CSS, but in my case the color can be dynamically chosen by the user.
Also, I'm curious how to apply the styles in code when dealing with a hierarchy of components.
You can assign the background color to be a looked-up color in the CSS file:
.tab-pane > .tab-header-area > .tab-header-background {
-fx-background-color: -fx-outer-border, -fx-text-box-border, my-tab-header-background ;
}
Now in code you can set the value of the looked-up color whenever you need to:
tabPane.setStyle("my-tab-header-background: blue ;");
SSCCE:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.Stage;
public class DynamicTabHeaderBackground extends Application {
private static final String TAB_HEADER_BACKGROUND_KEY = "my-tab-header-background" ;
#Override
public void start(Stage primaryStage) {
TabPane tabPane = new TabPane();
tabPane.setStyle(TAB_HEADER_BACKGROUND_KEY+": blue ;");
tabPane.getTabs().addAll(new Tab("Tab 1"), new Tab("Tab 2"));
tabPane.getSelectionModel().selectedIndexProperty().addListener((obs, oldIndex, newIndex) -> {
if (newIndex.intValue() == 0) {
tabPane.setStyle(TAB_HEADER_BACKGROUND_KEY+": blue ;");
} else {
tabPane.setStyle(TAB_HEADER_BACKGROUND_KEY+": green ;");
}
});
Scene scene = new Scene(tabPane, 400, 400);
scene.getStylesheets().add("dynamic-tab-header.css");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
with dynamic-tab-header.css containing the CSS code above.
Update
If you have multiple tab panes, you might want to consider the following variant of the CSS file:
.tab-pane {
my-tab-header-background: derive(-fx-text-box-border, 30%) ;
}
.tab-pane > .tab-header-area > .tab-header-background {
-fx-background-color: -fx-outer-border, -fx-text-box-border,
linear-gradient(from 0px 0px to 0px 5px, -fx-text-box-border, my-tab-header-background) ;
}
This basically emulates the default behavior, but allows you to modify the background on any particular tab pane by calling the tabPane.setStyle(...) code as before.
I want to add another css class for my component by example
.item{
-fx-background-color:blue;
-fx-border-radius:5;
}
.item-some{
-fx-background-color:red;
}
and in my code
control.getStyleClass().addAll("item","item-some");
but my control only get "item-some" style i want override only the color applying the second class as in css on web, can someone help me or give me a link to read about it?
thanks.
This basically behaves as expected for me: the item with both style classes gets the properties defined for both selectors. If there are conflicts, such as fx-background-color in this example, the one defined later in the css file overrides the ones before it.
Here's a complete test:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
public class MultipleStyleClassTest extends Application {
#Override
public void start(Stage primaryStage) {
Region region1 = new Region();
Region region2 = new Region();
region1.getStyleClass().add("style-class-1");
region2.getStyleClass().addAll("style-class-1", "style-class-2");
HBox root = new HBox(region1, region2);
Scene scene = new Scene(root);
scene.getStylesheets().add("multiple-style-class-test.css");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
multiple-style-class-test.css is
.style-class-1 {
-fx-min-width: 300 ;
-fx-min-height: 400 ;
-fx-background-color: blue ;
-fx-background-radius: 25 ;
}
.style-class-2 {
-fx-background-color: red ;
}
and the result is
As can be seen, both region1 and region2 get the -fx-min-height, -fx-min-width, and -fx-background-radius properties defined for style-class-1. region1 gets the -fx-background-color defined for style-class-1; region2 displays the background color defined for style-class-2.
I want to change the icon to my image, I've looked through the CSS reference guide but I can't seem to find anything relevant. Is it even possible? Doesn't matter if it is using CSS or declaratively from main JavaFX script.
Take a look at the sample code and images of how a custom slider is rendered in this AudioPlayer.
Also the JFXtras library has numerous gauges if you just want feedback rather than an interactive control.
Here is some sample css using the selector pointed out by invariant's answer. Note that I needed to add an -fx-padding specification at half the images dimensions in order for the whole image to display.
/** slider.css
place in same directory as SliderCss.java
ensure build system copies the css file to the build output path */
.slider .thumb {
-fx-background-image :url("http://icons.iconarchive.com/icons/double-j-design/diagram-free/128/piggy-bank-icon.png");
-fx-padding: 64;
}
/* Icon license: creative commons with attribution: http://www.doublejdesign.co.uk/products-page/icons/diagram */
Sample app:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class SliderCss extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws Exception {
VBox layout = new VBox();
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;");
layout.getChildren().setAll(new Slider());
layout.getStylesheets().add(getClass().getResource("slider.css").toExternalForm());
stage.setScene(new Scene(layout));
stage.show();
}
}
Sample program output:
you can change thumb of slider using css
.slider .thumb{
-fx-background-image :url("your image");
...// more customization
}
I know that this is an old question but I think I have a contribution to this solution.
If we want to use a unique slider or we want to modify the appearance of all the sliders the previous solution is more than enough. However, if we need only modify the appearance of only one slider the we need another approach.
What we gonna do is imagine that we have applied a based style to the main scene. But we don't want to add another css file just to modify the behavior of the slider. So the question is: How we can modify the slider style using our base css file?
The solution is simple setId() all the controls have this attribute. Now let's check out this class:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Created by teocci.
*
* #author teocci#yandex.com on 2018-Jul-06
*/
public class CustomSliderThumb extends Application
{
public static void main(String[] args) { launch(args); }
#Override
public void start(Stage stage) throws Exception
{
Slider slider = new Slider();
slider.setId("custom-slider");
VBox layout = new VBox();
layout.setId("base-layout");
layout.getChildren().setAll(slider);
Scene scene = new Scene(layout);
scene.getStylesheets().add("css/style.css");
stage.setScene(scene);
stage.show();
}
}
In this example, we created a slider and set its id as "custom-slider". Then we added this slider to a VBox layout and, finally, we added the layout to the scene that has the style.css
Now lets check the style.css and how to use the id selector to apply a custom style. Remember to specify -fx-pref-height and -fx-pref-width with the dimensions of the image or if is a square -fx-padding at half the image side dimension for displaying the whole image.
#custom-slider .thumb {
-fx-background-image :url("https://i.imgur.com/SwDjIg7.png");
-fx-background-color: transparent;
-fx-padding: 24;
/*-fx-pref-height: 48;*/
/*-fx-pref-width: 48;*/
}
#custom-slider .track {
-fx-background-color: #2F2F2F;
}
#base-layout {
-fx-background-color: lightgray;
-fx-padding: 10px;
}
Sample program output:
If you want to remove the thumb background color and only have the image(semi-transparent ones like round button) then you should also -fx-background-color:transparent; unless you will have the background
.slider .thumb {
-fx-background-image :url("sider-round-thumb-image.png");
-fx-padding: 16; /* My thumb image is 33x33 pixels,so padding is half */
-fx-pref-height: 28;
-fx-pref-width: 28;
-fx-background-color:transparent;
}