how about css class prescedence in javafx - css

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.

Related

Can I only target bottom border at JavaFX Styling?

can I somehow only style the bottom border of an textfield?
I already tried
textfield.setStyle("-fx-border-bottom-color: #FF0000");
but it hasn't worked.
Is there an possibility to color the bottom border??
Greetings
MatsG23
Here is a quick and dirty example of how that can be done.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TextFieldStyleTest extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
root.setCenter(vBox);
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER);
vBox.getChildren().add(hBox);
TextField textField = new TextField("Hello World");
textField.setAlignment(Pos.BASELINE_CENTER);
hBox.getChildren().add(textField);
textField.setStyle("-fx-border-color: red; -fx-border-width: 0 0 10 0;");
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
class TextFieldStyleTestLauncher {public static void main(String[] args) {TextFieldStyleTest.main(args);}}
Yes, it is possible to give each side a different color. From the JavaFX CSS Reference Guide, for Region:
CSS Property: -fx-border-color
Values: <paint> | <paint> <paint> <paint> <paint> [ , [<paint> | <paint> <paint> <paint> <paint>] ]*
Default: null
Comments: A series of paint values or sets of four paint values, separated by commas. For each item in the series, if a single paint value is specified, then that paint is used as the border for all sides of the region; and if a set of four paints is specified, they are used for the top, right, bottom, and left borders of the region, in that order. If the border is not rectangular, only the first paint value in the set is used.
Note: The above is actually from one row of a table, but Stack Overflow doesn't give a way of formatting things in a table.
Meaning you can target the bottom border only by using:
.text-field {
-fx-border-color: transparent transparent red transparent;
}
The -fx-border-width CSS property (and really all the CSS properties dealing with the Region#background and Region#border properties) behaves the same way. This means you can accomplish the same thing by setting the width of every side but the bottom to zero, just like in mipa's answer.
Here's an exaple using inline CSS (i.e. setStyle):
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
TextField field = new TextField("Hello, World!");
field.setStyle("-fx-border-color: transparent transparent red transparent;");
field.setMaxWidth(Region.USE_PREF_SIZE);
primaryStage.setScene(new Scene(new StackPane(field), 300, 150));
primaryStage.show();
// Remove blue outline from when TextField is focused. This
// makes it easier to see the red border.
primaryStage.getScene().getRoot().requestFocus();
}
}
Which gives the following output:
Note that most of the "borders" added by modena.css (the default user-agent style sheet in JavaFX 8+) are not actually borders. Instead, they're multiple backgrounds with different insets.

Javafx linear-gradient repeat behaviour

Javafx linear-gradient repeat seems to reflect the colours rather than repeat.
I wrote a simple application to show what I see when using linear-gradient with repeat to create a striped pattern in my application on a custom Node (a StackPane). In my application this are added as overlays to a XYChart and their height varies. Using a Rectangle wasn't working well which is why I use a Stackpane and set a style on it rather than creating the LinearGradient programmatically.
The colour list is dynamic and varies in size in the application.
The issue is the way linear-gradient flips the list and reflects the colours on each repeat rather than just repeat.
This link describes a similar issue but just adding in endless stops seemless like a messy solution for my issue, it would be much better to add the colours once and repeat.
linear gradient repeat on css for javafx
java.util.List;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
List<Color> colors = Arrays.asList( Color.RED,Color.BLUE,Color.YELLOW,Color.GREEN);
StackPane stackPane = new StackPane();
stackPane.setStyle(getLinearGradientStyle(colors));
root.setCenter(stackPane);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
catch (Exception e) {
e.printStackTrace();
}
}
private String getLinearGradientStyle(List<Color> colors) {
StringBuilder stringBuilder = new StringBuilder("-fx-background-color: linear-gradient(from 0px 0px to 10px 10px, repeat,");
for (int i = 0; i < colors.size(); i++) {
stringBuilder.append("rgb(")
.append((int) (colors.get(i).getRed() * 255)).append(",")
.append((int) (colors.get(i).getGreen() * 255)).append(",")
.append((int) (colors.get(i).getBlue() * 255))
.append(")")
.append(" ").append(getPercentage(i+1, colors.size()+1) );
if (i < colors.size() - 1) {
stringBuilder.append(",");
}
}
stringBuilder.append(");");
System.out.println("Main.getLinearGradientStyle():"+stringBuilder);
return stringBuilder.toString();
}
private String getPercentage(float i, int size) {
return (((1.0f / size) * 100 )*i)+ "%";
}
public static void main(String[] args) {
launch(args);
}
Here's a CSS3 example using repeating-linear-gradient:
https://tympanus.net/codrops/css_reference/repeating-linear-gradient/
scroll down to the following text: will create a striped background, where each linear gradient is a three-stripe gradient, repeated infinitely (this is the example)
My example uses a diagonal pattern which is what I need but the above example shows what I'd like to see in terms of solid repeating colours with out reflection in normal css.
Thanks for any help
This looks like a bug. If you run the following example (moved the CSS into a file):
Main.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Region region = new Region();
region.backgroundProperty().addListener((obs, ov, nv) ->
System.out.println(nv.getFills().get(0).getFill()));
Scene scene = new Scene(region, 500, 300);
scene.getStylesheets().add("Main.css");
primaryStage.setScene(scene);
primaryStage.show();
}
}
Main.css
.root {
-fx-background-color: linear-gradient(from 0px 0px to 10px 10px, repeat, red 20%, blue 40%, yellow 60%, green 80%);
}
You'll see the following printed out:
linear-gradient(from 0.0px 0.0px to 10.0px 10.0px, reflect, 0xff0000ff 0.0%, 0xff0000ff 20.0%, 0x0000ffff 40.0%, 0xffff00ff 60.0%, 0x008000ff 80.0%, 0x008000ff 100.0%)
As you can see, despite using "repeat" in the CSS the LinearGradient that is created uses "reflect".
There is likely nothing you can do about this bug yourself, but if you don't mind setting the background in code (or probably even FXML) then the following should do what you want:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
LinearGradient gradient = new LinearGradient(0, 0, 10, 10, false, CycleMethod.REPEAT,
new Stop(0.2, Color.RED),
new Stop(0.4, Color.BLUE),
new Stop(0.6, Color.YELLOW),
new Stop(0.8, Color.GREEN)
);
Region region = new Region();
region.setBackground(new Background(new BackgroundFill(gradient, null, null)));
Scene scene = new Scene(region, 500, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
}
You can move the creation of the LinearGradient into a method that takes an arbitrary number of Colors, just like you're currently doing.
If you're interested, I believe the bug is located in javafx.css.CssParser around line 1872 (in JavaFX 12):
CycleMethod cycleMethod = CycleMethod.NO_CYCLE;
if ("reflect".equalsIgnoreCase(arg.token.getText())) {
cycleMethod = CycleMethod.REFLECT;
prev = arg;
arg = arg.nextArg;
} else if ("repeat".equalsIgnoreCase(arg.token.getText())) {
cycleMethod = CycleMethod.REFLECT;
prev = arg;
arg = arg.nextArg;
}
As you can see, it erroneously sets the CycleMethod to REFLECT when the text is equal to "repeat".
A bug report has been filed: JDK-8222222 (GitHub #437). Fix version: openjfx13.

Disable spacing between items in TextFlow in JavaFX

I'm trying to make a line of text which consists of a name and a string of text. I want the name to be a hyperlink and the rest to be just plain text.
I thought TextFlow would be good for this, but the problem is it automatically puts a single space between the hyperlink and the text. What if I want the TextFlow to be for example
Jane's awesome
The TextFlow will make that a
Jane 's awesome
Is there a method or CSS property to disable this behaviour?
Solution
You can remove the padding via a CSS style:
.hyperlink {
-fx-padding: 0;
}
Or you can do it in code if you wish:
link.setPadding(new Insets(0));
Background
The default setting can be found in the modena.css file in the jfxrt.jar file packaged with your JRE distribution and it is:
-fx-padding: 0.166667em 0.25em 0.166667em 0.25em; /* 2 3 2 3 */
Sample application
In the sample screenshot the second hyperlink has focus (hence its dashed border).
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Hyperlink;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
public class HyperSpace extends Application {
#Override
public void start(Stage stage) {
TextFlow textFlow = new TextFlow(
unstyle(new Hyperlink("Jane")),
new Text("'s awesome "),
unstyle(new Hyperlink("links"))
);
stage.setScene(new Scene(new Pane(textFlow)));
stage.show();
}
private Hyperlink unstyle(Hyperlink link) {
link.setPadding(new Insets(0));
return link;
}
public static void main(String[] args) {
launch(args);
}
}

JavaFX apply rotate to an image from CSS

I'm wondering if there is a way to apply some transformations (i.e. rotate) to an image setted to some button. I am using css to specify all images by such way:
.custom-button {
-fx-graphic: url("imgs/buttons/button.png");
...
}
.custom-button:hover {
-fx-graphic: url("imgs/buttons/button_hover.png");
...
}
.custom-button:selected {
-fx-graphic: url("imgs/buttons/button_selected.png");
...
}
I want to specify such transformation here in css as well.
How can I achieve that? I am supposing to find something like:
.custom-button .graphic {
-fx-rotate: 90;
}
Let's start with an example application:
Main.java
package application;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Button button = new Button("Button");
VBox vBox = new VBox(button);
vBox.setPadding(new Insets(10.0));
Scene scene = new Scene(vBox, 200, 100);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
System.out.println();
}
public static void main(String[] args) {
launch(args);
}
}
application.css
.button {
-fx-graphic: url(image.png);
}
Result
Method 1 (find out which class is used for the image)
This can be easily done using a debugger (set a breakpoint on println() and check the content of button.graphic.value). The class which is used here is ImageView. This means the image can be rotated using:
.button .image-view {
-fx-rotate: 45;
}
Result
Method 2 (set a custom class for the graphic object)
This can be done using a ChangeListener:
button.graphicProperty().addListener((ChangeListener<Node>) (observable, oldValue, newValue) -> {
newValue.getStyleClass().add("my-class");
});
Then the following can be used to rotate the image:
.my-class {
-fx-rotate: 45;
}
Result
Padding
You might need to add additional padding to the button, if the image takes up too much space:
.button {
-fx-graphic: url(image.png);
-fx-graphic-text-gap: 10;
-fx-label-padding: 5 0 5 5;
}
Result

Javafx ImageView Tooltip style

I have made a global style to be applied to all tooltips, and it is working correctly except when then the tooltip is installed onto an ImageView. If I add the tooltip to the ImageView's parent (a HBox), the styling is correct, so it can't be a problem with the stylesheet not being added.
The css style looks like this:
.tooltip
{
-fx-border-color: gray;
-fx-border-radius: 5.0 5.0 5.0 5.0;
-fx-background-radius: 5.0 5.0 5.0 5.0;
-fx-background-color: white;
-fx-text-fill: black;
-fx-wrap-text: true;
}
Adding tooltip to imageview (style doesn't work):
Tooltip.install(imageviewFormat, formatTooltip);
Adding tooltip to parent (style does work):
Tooltip.install(imageviewFormat.getParent(), formatTooltip);
Am I doing something stupid here, or does ImageView not inherit the css from its parent. Any insight would be appreciated.
Update
The following example has this behavior, where style.css contains the same tooltip styleclass.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Tooltip;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Test extends Application
{
public static void main(String[] args) throws Exception
{
launch(args);
}
#Override
public void start(Stage primarystage) throws Exception
{
HBox root = new HBox();
root.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
ImageView imageView = new ImageView("http://www.samjarman.co.nz/images/so.png");
root.getChildren().add(imageView);
Tooltip.install(imageView, new Tooltip("Tooltip")); // Doesn't work
// Tooltip.install(imageView.getParent(), new Tooltip("Tooltip")); // Works
Scene scene = new Scene(root);
primarystage.setScene(scene);
primarystage.show();
}
}
Thanks

Resources