I have initialized a decorator into my project, which was at first fine and nice looking. But now I have encountered several problems, I did not figure out how to change the border color (currently it is black). I also want to remove the button which resizes the window.
Here is the code which touches the decorator:
public void start(Stage primaryStage){
JFXDecorator decorator = new JFXDecorator(primaryStage, gridContainer);
decorator.setCustomMaximize(false);
decorator.setText("Window Title");
decorator.setStyle("-fx-background-color: #ffffff; -fx-font-family:'Franklin Gothic Medium'");
Scene scene= new Scene(decorator, 350, 500, Color.BEIGE);
}
A couple of minutes later I came up with a simple but adequate solution. I have created a decorator class in my css file.
Here is the code I have added into my css file:
.jfx-decorator{
-fx-decorator-color: white;
}
.jfx-decorator .jfx-decorator-buttons-container{
-fx-background-color: -fx-decorator-color;
}
.jfx-decorator .resize-border{
-fx-border-color: -fx-decorator-color;
-fx-border-width: 0 4 4 4;
}
Related
I am working on a Javafx application and I tried to add some Labels, Buttons and Texts, which resizes when the user resizing the Scene. All Nodes are inside a VBox, which itself is inside a StackPane.
My test application:
public class Test extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(final Stage primaryStage)
{
StackPane pane = new StackPane();
VBox box = new VBox();
box.setAlignment(Pos.CENTER);
Label l = new Label("Label");
Text t = new Text("Text");
t.getStyleClass().add("test");
Button b = new Button("Button");
pane.heightProperty().addListener(listener ->
{
double h = pane.getHeight()/5;
l.setFont(Font.font(l.getFont().getFamily(), h));
t.setFont(Font.font(t.getFont().getFamily(), h));
b.setFont(Font.font(b.getFont().getFamily(), h));
});
box.getChildren().addAll(l, t, b);
pane.getChildren().add(box);
primaryStage.setScene(new Scene(pane));
primaryStage.getScene().getStylesheets().add(Path.of("test.css").toUri().toString());
primaryStage.show();
}
}
If I resize the Stage it works as expected. But unfortunately only with pure Java code.
Because after adding my css file, the Labeled controls behave different. While the Text elements continue to change in size, the Labels and Buttons does not change their size anymore.
My css file, which does not work:
.label
{
-fx-text-fill: red;
-fx-font-family: impact;
}
.test
{
-fx-fill: red;
-fx-font-family: impact;
-fx-font-size: 2em;
}
.button
{
-fx-text-fill: red;
-fx-font-size: 2em;
}
I asked myself what I did wrong and have tested different css states. I found out, when I omit font values in css it works, otherwise it does not. Therewhile it does not matter which font value occurs, only one font value is required to miss the behavior.
My css file, which works:
.label
{
-fx-text-fill: red;
//-fx-font-family: impact;
}
.test
{
-fx-fill: red;
-fx-font-family: impact;
-fx-font-size: 2em;
}
.button
{
-fx-text-fill: red;
//-fx-font-size: 2em;
}
1. Question: -has changed, see below-
Do I missunderstand something about css and Javafx, or did I something wrong in my css file or is there a bug?
2. Question: -solved-
Have I to put the font values with java code or is there an other way to add the font?
Thank You for helping!
Update
As recommended I have studying the follow guide:
https://openjfx.io/javadoc/14/javafx.graphics/javafx/scene/doc-files/cssref.html
The JavaFX CSS implementation applies the following order of precedence:
The implementation allows designers to style an application by using style sheets to override property values set from code. For example, a call to rectangle.setFill(Color.YELLOW) can be overridden by an inline‑style or a style from an author stylesheet. This has implications for the cascade; particularly, when does a style from a style sheet override a value set from code? The JavaFX CSS implementation applies the following order of precedence: a style from a user agent style sheet has lower priority than a value set from code, which has lower priority than a Scene or Parent style sheet. Inline styles have highest precedence. Style sheets from a Parent instance are considered to be more specific than those styles from Scene style sheets.
In my case this means, I will use the inline style to make it proper.
thus the 2. Question is solved
But, because of Parent style sheet > value set from code, it also means, all Nodes are not allowed to change theire size, even the Text Node.
Therefore I changed my 1. Question to:
Why does the JavaFX CSS order of precedence differ between Text and Controls
Question 1:
It's not a bug, it's a conflict of priorities. .setFont() has a lower priority than that CSS. Just replace .setFont() to .setStyle() and sample will work as you planned:
l.setStyle("-fx-font-size:" + h + ";");
t.setStyle("-fx-font-size:" + h + ";");
b.setStyle("-fx-font-size:" + h + ";");
Question 2:
Try to keep all about styles in CSS. It's the best practice.
Can someone please tell me why -fx-text-fill in the below example doesn't work to change the font color? -fx-stroke is something I've tried as well. Thanks!
Java File:
package SimpleTextFromCSS;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class Main extends Application
{
#Override
public void start(Stage primaryStage)
{
GridPane rootGP = new GridPane();
Label centerText = new Label("Sample text.");
rootGP.getChildren().add(centerText);
Scene scene = new Scene(rootGP,1200,800);
scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
primaryStage.setScene(mainScene);
primaryStage.show();
}
}
public static void main(String[] args)
{
launch(args);
}
}
CSS:
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-text-fill: blue;
}
As pointed out in the comments (thanks to #Slaw), the -fx-text-fill property is not inherited by default, so setting it for your root pane will not allow it to propagate down to the labels in your UI. A possible fix would be to define the property for, say .label, but a better approach is to hook into the "theming" functionality of the default style sheet ("modena"). Admittedly, the documentation on this is pretty thin, but reading the comments in the CSS source code, particularly at the top of the file, indicate how this is intended to work.
Modena defines a "looked-up color" called -fx-text-background-color, which is used for text painted on top of a background filled with -fx-background-color. A Label is such a text, and the default style sheet sets the text fill of a label to -fx-text-background-color.
So one approach is to redefine the -fx-text-background-color value:
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-text-background-color: blue;
}
If you want to be a little more sophisticated, the default value of -fx-text-background-color is actually a "ladder", which picks a color depending on the intensity of the background. It is itself defined in terms of three other colors:
-fx-light-text-color (for dark backgrounds, which defaults to white),
-fx-mid-text-color (for light backgrounds, which defaults to a light grey), and
-fx-dark-text-color (for medium backgrounds, which defaults to black).
So if you want a solution that would be visually robust to changes in the background of a label, you could do
.root{
-fx-font-family: "Broadway";
-fx-font-size: 50pt;
-fx-dark-text-color: navy ;
-fx-mid-text-color: blue ;
-fx-light-text-color: skyblue ;
}
I have a toggle button in my program that starts/stops a script. I would like for this button to be green and say "START" when the button is not selected, and red and say "STOP" when it is selected. More importantly, I would like the unselected hover color to be a slightly darker version of the original green, and the selected hover color to be a slightly darker version of the red color. My current CSS for this button looks like this:
#startStopButton {
-fx-border-color:#d4d4d4;
-fx-background-color:#85eca5;
-fx-background-image: url("startButton.png");
-fx-background-size: 50px;
-fx-background-repeat: no-repeat;
-fx-background-position: 80% 50%;
-fx-alignment: CENTER_LEFT;
-fx-effect: dropshadow(three-pass-box, #e7e7e7, 15, 0, 0, 0);
}
#startStopButton:hover {
-fx-background-color:#80dc9c;
}
#startStopButton:selected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
#startStopButton:selected:focused{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
Currently, this will work fine, except for when the button turns red. In this case, there is no hover effect. Within my FXML controller, there is a function that is activated every time this button is clicked:
private void startStopClick()
{
if(startStopButton.isSelected())
{
startStopButton.setText(" STOP");
// startStopButton.setStyle()
}
else {
startStopButton.setText(" START");
}
}
Is there any way to 1) set the button text within CSS so that I can leave that out of my controller?
2) Get the current toggle button state in CSS, so that I can have multiple hover effects. For example, something like this:
#startStopButton:unselected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
If there is no way to do this in CSS, can I set the hover styles in the Java code in the FXML controller?
CSS properties are only available for the look of nodes. With a few exceptions the basic JavaFX nodes don't allow you to specify content via CSS. The text property of buttons is no exception; it cannot be set using CSS.
As for the colors: The rules occuring last override values assigned by rules with the same precedence occuring before them. This means the background color assigned by the rules for #startStopButton:selected and #startStopButton:selected:focused always override the color #startStopButton:hover assigns.
Since in both cases you want a darker color when hovering, the derive function and a lookedup color may work for you.
Example
#Override
public void start(Stage primaryStage) {
ToggleButton btn = new ToggleButton();
btn.getStyleClass().add("start-stop");
btn.textProperty().bind(Bindings.when(btn.selectedProperty()).then(" STOP").otherwise(" START"));
Pane p = new Pane(btn);
Scene scene = new Scene(p);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
style.css
.start-stop.toggle-button {
base-color: #85eca5;
-fx-background-color: base-color;
}
.start-stop.toggle-button:selected {
base-color: #ff6060;
}
.start-stop.toggle-button:hover {
-fx-background-color: derive(base-color, -20%);
}
If you cannot use derive since you need to specify different colors for all 4 states you could still rely on looked-up colors to avoid relying on the rule ordering:
.start-stop.toggle-button {
unselected-color: blue;
selected-color: yellow;
-fx-background-color: unselected-color;
}
.start-stop.toggle-button:hover {
unselected-color: red;
selected-color: green;
}
.start-stop.toggle-button:selected {
-fx-background-color: selected-color;
}
I've been into custom controls with JavaFX recently and was wondering what the best way is to create a button that simply is an image. For instance here on Stack Overflow we have these buttons (I suppose that in reality they are links but I want the same effect in JavaFX) that do not look like buttons at all.
What is the best way of creating something similar in JavaFX? I know you can add images to buttons but is there then also a way of completely removing the background (I suspect there is)?
I use a custom ImageButton class in my projects. This is similar to fabian's approach, but uses an ImageView. It is also a bit simpler to implement, in my view.
public class ImageButton extends Button {
private final String STYLE_NORMAL = "-fx-background-color: transparent; -fx-padding: 2, 2, 2, 2;";
private final String STYLE_PRESSED = "-fx-background-color: transparent; -fx-padding: 3 1 1 3;";
public ImageButton(Image originalImage, double h, double w) {
ImageView image = new ImageView(originalImage);
image.setFitHeight(h);
image.setFitHeight(w);
image.setPreserveRatio(true);
setGraphic(image);
setStyle(STYLE_NORMAL);
setOnMousePressed(event -> setStyle(STYLE_PRESSED));
setOnMouseReleased(event -> setStyle(STYLE_NORMAL));
}
}
Then you just need to pass it the Image and dimensions:
ImageButton newButton = new ImageButton(new Image("icon.png"), 16, 16);
Just set the graphic property of the button accordingly.
Since stackoverflow uses svg paths, the following example uses SVGPath, but it could easily be changed to an ImageView and the scaling could replaced with setting fitWidth/fitHeight. If you do want to use ImageView though, you should be aware of the fact that ImageView does not provide a fill property and you need to work with opacity or with different images instead.
public static Button createIconButton(String svg) {
SVGPath path = new SVGPath();
path.setContent(svg);
Bounds bounds = path.getBoundsInLocal();
// scale to size 20x20 (max)
double scaleFactor = 20 / Math.max(bounds.getWidth(), bounds.getHeight());
path.setScaleX(scaleFactor);
path.setScaleY(scaleFactor);
path.getStyleClass().add("button-icon");
Button button = new Button();
button.setPickOnBounds(true); // make sure transparent parts of the button register clicks too
button.setGraphic(path);
button.setAlignment(Pos.CENTER);
button.getStyleClass().add("icon-button");
return button;
}
#Override
public void start(Stage primaryStage) {
// the following svg paths were copied from the stackoverflow website
HBox root = new HBox(
createIconButton("M15.19 1H4.63c-.85 0-1.6.54-1.85 1.35L0 10.79V15c0 1.1.9 2 2 2h16a2 2 0 0 0 2-2v-4.21l-2.87-8.44A2 2 0 0 0 15.19 1zm-.28 10l-2 2h-6l-2-2H1.96L4.4 3.68A1 1 0 0 1 5.35 3h9.12a1 1 0 0 1 .95.68L17.86 11h-2.95z"),
createIconButton("M15 2V1H3v1H0v4c0 1.6 1.4 3 3 3v1c.4 1.5 3 2.6 5 3v2H5s-1 1.5-1 2h10c0-.4-1-2-1-2h-3v-2c2-.4 4.6-1.5 5-3V9c1.6-.2 3-1.4 3-3V2h-3zM3 7c-.5 0-1-.5-1-1V4h1v3zm8.4 2.5L9 8 6.6 9.4l1-2.7L5 5h3l1-2.7L10 5h2.8l-2.3 1.8 1 2.7h-.1zM16 6c0 .5-.5 1-1 1V4h1v2z"));
Scene scene = new Scene(root);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
style.css
/* set default fill of svg path */
.icon-button .button-icon {
-fx-fill: #888888;
}
/* set default fill of svg path */
.icon-button:focused {
-fx-background-color: lightblue;
-fx-background-radius: 0;
}
/* remove default button style & set size */
.icon-button {
-fx-background-color: transparent, transparent, transparent, transparent, transparent;
-fx-pref-height: 30;
-fx-pref-width: 30;
-fx-min-height: 30;
-fx-min-width: 30;
-fx-max-height: 30;
-fx-max-width: 30;
}
/* modify svg path fill for hovered/pressed button */
.icon-button:pressed .button-icon,
.icon-button:hover .button-icon {
-fx-fill: #444444;
}
Despite this being an old post, it still might be nice for those using a SceneBuilder to know that you can do this with a Button and an ImageView:
(I am using Gluon SceneBuilder)
Button Setup:
Under 'Graphic' set the Display to 'GRAPHIC_ONLY'
Then for the in-line CSS use: -fx-background-colour: transparent;
ImageView:
Set the image to whatever you want
In the 'Hierarchy' pick up and drop the ImageView onto the button
What it looks like when done:
Transparent Button ~ with only Image shown
How to change the icon size of a color picker in javaFX. I'm having a problem, I can not increase the icon size of a color picker in JavaFX, does anyone know how to change the size of the button icon?
icon its small :(
Setting the CSS attributes -fx-color-rect-width and -fx-color-rect-width will change size of the rectangle displayed. Setting fx-font-size will change the size of the arrow.
Note that some of these attributes are not documented in the official JavaFX CSS reference, so I guess future JavaFX iterations could change them without notice. Still, at this stage, I think that is probably unlikely and the attributes are pretty safe to use. To determine the undocumented CSS attributes, I looked at the source code for the ColorPickerSkin.
pickme.css
.large-rect-picker {
-fx-color-rect-width: 60px;
-fx-color-rect-height: 60px;
-fx-color-label-visible: false;
-fx-min-width: 150px;
-fx-min-height: 100px;
-fx-pref-width: 150px;
-fx-pref-height: 100px;
}
.large-rect-picker > .arrow-button {
-fx-font-size: 30px;
}
PickMe.java
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ColorPicker;
import javafx.stage.Stage;
public class PickMe extends Application {
#Override
public void start(Stage stage) {
ColorPicker colorPicker = new ColorPicker();
colorPicker.getStyleClass().add("large-rect-picker");
stage.setScene(new Scene(new Group(colorPicker)));
stage.getScene().getStylesheets().add(
PickMe.class.getResource(
"pickme.css"
).toExternalForm()
);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Aside info on asking questions
It is difficult to know exactly what you want as you aren't really explicit in the question. For instance what do you mean by icon? The rectangle or the down arrow or both? What about the display that is popped up when you click on that arrow, should that change at all or stay the same? For future questions, I recommend you be more specific about what you are trying to achieve and how it differs from what you have. Showing code which produces what you have might also help others solve your issue. Hopefully the info above is enough for you to modify it to accomplish what you wish.
You can access and customize color picker by using css:
ColorPicker
Style class: color-picker
Substructure
color display node — Label
arrow-button — StackPane
arrow — StackPane
The ColorPicker control has all the properties and pseudo‑classes of ComboBase
Example
.color-picker .label {
-fx-background-color: red;
-fx-text-fill: null;
-fx-graphic: url("1487868456_Other_Antivirus_Software.png");//This is icon of Color picker label
}
Result:
As far as I know you cant use -fx-width/-fx-height at all and you cant use percentage values for it. The width and height of elements are read-only. You can set -fx-pref-width, -fx-pref-height, -fx-max-width, -fx-min-width, -fx-max-height, -fx-min-height ,-fx-border-width and -fx-border-height to adjust the size of Java FX elements.
.picker-color {
-fx-border-color:white ;
-fx-border-width:40;
}