Can I only target bottom border at JavaFX Styling? - css

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.

Related

when i add a button the scene color disappear (javaFx) [duplicate]

Why MenuBar changes the background color of the scene in this code sample? It should be blue but it is white.
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
scene.setFill(Color.rgb(0, 0, 255));
primaryStage.setScene(scene);
primaryStage.show();
MenuBar menuBar = new MenuBar();
}
public static void main(String[] args) {
launch(args);
}
}
The white background you are seeing is the background of the BorderPane. This background color is set when the default stylesheet is loaded.
The reason that you only see this when the MenuBar is created is that CSS is only applied (unless you force it) when the first control is created. This is by design, to prevent the overhead of loading stylesheets and applying CSS for applications that don't need them (e.g. for games or simulations that manage all their own graphics). Since all controls are styled by CSS, just instantiating a control forces CSS to be applied.
The fix is to make the background of the BorderPane transparent.
Either
root.setStyle("-fx-background-color: transparent;");
or
root.setBackground(Background.EMPTY);
Of course, since you have to set the background of the root pane, you may as well set that to blue instead of setting the fill of the Scene:
BorderPane root = new BorderPane();
root.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
Scene scene = new Scene(root,400,400);
Or, you can use an external style sheet:
.root {
-fx-background-color: blue ;
}
Also see this related post and this OTN discussion.

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.

JavaFX - setStyle() changes not showing

I am creating a JavaFX application and I am having problems changing the background colors for certain components. For the buttons I am able to change their background radius, but not their background color. For the TableView I am unable to change the background color as well.
Here is my code and a picture of what I am seeing.
import javafx.geometry.Pos;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableView;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class HomeUI extends Application {
private TableView transactionTable = new TableView();
private Button importButton = new Button("Import");
private Button trendButton = new Button("Trends");
private Button transactionButton = new Button("Transactions");
public static void main(String[] args){
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
// Set the text of defined fields
primaryStage.setTitle(" Budget Tracker");
// Import button information
// Create Anchor pane
AnchorPane anchorPane = new AnchorPane();
anchorPane.setPrefHeight(668.0);
anchorPane.setPrefWidth(1112.0);
anchorPane.setStyle("-fx-background-color: #545e75;");
// VBox to hold all buttons
VBox vBox = new VBox();
vBox.setPrefWidth(195);
vBox.setPrefHeight(668);
vBox.prefHeight(668);
vBox.prefWidth(203);
vBox.setStyle("-fx-background-color: #82a0bc;");
vBox.setLayoutX(0);
vBox.setLayoutY(0);
vBox.setAlignment(Pos.CENTER);
// importButton settings
importButton.setMnemonicParsing(false);
importButton.setPrefWidth(300);
importButton.setPrefHeight(80);
importButton.setStyle("-fx-background-color: #cacC9cc");
importButton.setStyle("-fx-background-radius: 0;");
// trendButton settings
trendButton.setPrefWidth(300);
trendButton.setPrefHeight(80);
trendButton.setStyle("-fx-background: #bcbdc1");
trendButton.setStyle("-fx-background-radius: 0");
// transactionButton settings
transactionButton.setPrefWidth(300);
transactionButton.setPrefHeight(80);
transactionButton.setStyle("-fx-base: #aeacb0");
transactionButton.setStyle("-fx-background-radius: 0");
// Add buttons to the vBox
vBox.getChildren().addAll(importButton, trendButton, transactionButton);
// TableView settings
transactionTable.setPrefHeight(568);
transactionTable.setPrefWidth(694);
transactionTable.setLayoutX(247);
transactionTable.setLayoutY(50);
transactionTable.setStyle("-fx-background-color: CAC9CC;");
transactionTable.setEditable(false);
// Add components to anchorPane
anchorPane.getChildren().addAll(vBox, transactionTable);
// Add anchorPane to scene and show it
primaryStage.setScene(new Scene(anchorPane));
primaryStage.show();
}
}
Buttons
By setting the style property, you replace the old style. Doing this multiple times does not combine the styles. You should set a value that combines the rules.
Instead of
transactionButton.setStyle("-fx-base: #aeacb0");
transactionButton.setStyle("-fx-background-radius: 0");
use
transactionButton.setStyle("-fx-base: #aeacb0; -fx-background-radius: 0;");
TableView
TableView shows little of it's own background. Most coloring you'll see is the background color of the TableRows that are added as descendants of the TableView. You'll need to use a CSS stylesheet to do this though (unless you want to use a rowFactory to do the styling).
.table-view .table-row-cell {
-fx-background-color: #CAC9CC;
}

Java FX, weird behavior from Label

I have managed to fix the below issue by using the Text class instead of Label, however I would still like to understand the behavior.
I am trying to create a pane with an image and some text below that image.
I want both the text and the image to be centered inside of the pane.
I also want the text to stick to the bottom of the pane while the image to stick to the top of the pane.
Below is the rough code that achieves what I want. The problem is, If I run the code, the image comes out a little off center. The label also doesn't appear.
If I resize the stage with my mouse, the layout seems to fix itself. The image becomes fully centered and the text appears. Please explain, is this some kind of a bug?
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import static javafx.beans.binding.Bindings.subtract;
public class TestApp extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
AnchorPane pane = new AnchorPane();
BorderPane borderPane = new BorderPane();
ImageView imageView = new ImageView();
Label label = new Label("some text");
AnchorPane.setBottomAnchor(borderPane, 0.0);
AnchorPane.setTopAnchor(borderPane, 0.0);
AnchorPane.setLeftAnchor(borderPane, 0.0);
AnchorPane.setRightAnchor(borderPane, 0.0);
imageView.setPreserveRatio(true);
pane.getChildren().add(borderPane);
borderPane.setTop(imageView);
borderPane.setBottom(label);
BorderPane.setAlignment(imageView, Pos.CENTER);
BorderPane.setAlignment(label, Pos.CENTER);
imageView.fitHeightProperty().bind(subtract(pane.heightProperty(), label.heightProperty()));
imageView.setImage(new Image("file:C:\\pathToFile.jpg"));
primaryStage.setScene(new Scene(pane, 200, 150));
primaryStage.show();
}
}

why is my circle filled Black even though i haven't set it to be filled

I am currently working on an assignment where i must print a circle in the center of the primary stage and 4 buttons on the bottom center area of the primary stage which move the circle, up, down, left, and right when clicked. when i run my code, my circle is filled in with the color black. I have set the stroke of the circle to be black but i have not set the circle to be filled black. I know i can just set my circle to be filled white and somewhat solve the problem, but i am wondering if anyone knows why this is happening. Also, i cannot get the Circle and the buttons to print into the same window. I can get either the circle to print by setting the primaryStage to the scene or print the buttons by setting the scene to hBox and then setting the primaryStage to the scene. How should i best change my code so that the buttons and the circle are both displayed?
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.geometry.Pos;
import javafx.event.EventHandler;
import javafx.event.ActionEvent;
public class Btest extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Create a border pane
BorderPane pane = new BorderPane();
// create Hbox, set to bottom center
HBox hBox = new HBox();
hBox.setSpacing(10);
hBox.setAlignment(Pos.BOTTOM_CENTER);
Button btLeft = new Button("Left");
Button btDown = new Button("Down");
Button btUp = new Button("Up");
Button btRight = new Button("Right");
hBox.getChildren().addAll(btLeft, btDown, btUp, btRight);
// Lambda's
btLeft.setOnAction((e) -> {
System.out.println("Process Left");
});
btDown.setOnAction((e) -> {
System.out.println("Process Down");
});
btUp.setOnAction(e -> {
System.out.println("Process Up");
});
btRight.setOnAction((e) -> {
System.out.println("Process Right");
});
pane.setCenter(new CenteredCircle("Center"));
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 300, 300);
//set stage and display
primaryStage.setTitle("ShowBorderPane"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
}
public static void main(String[] args) {
Application.launch(args);
}
}
// create custom class for circle
class CenteredCircle extends StackPane {
public CenteredCircle(String title) {
setPadding(new Insets(11.5, 12.5, 13.5, 14.5));
Circle circle = new Circle();
circle.setStroke(Color.BLACK);
circle.setCenterX(50);
circle.setCenterY(50);
circle.setRadius(50);
getChildren().add(circle);
}
}
"Why is my circle filled Black even though i haven't set it to be filled?"
Because the default color is black. See the doc of Shape.setFill() method:
Defines parameters to fill the interior of an Shape using the settings
of the Paint context. The default value is Color.BLACK for all shapes
except Line, Polyline, and Path. The default value is null for those
shapes.
"... Also, i cannot get the Circle and the buttons to print into the same window."
Put the Hbox to the parent BorderPane, for instance into the bottom:
pane.setBottom( hBox );

Resources