JavaFX style class won't refresh
Asked Answered
S

5

11

I'm adding a style class to an node if it's selected and then remove it if I select other item. Even if I remove the style class the style wont refresh so it wont go back to normal state:

admin_category_label.getStyleClass().remove(admin_category_label.getStyleClass().indexOf("selected"));
admin_category_label.getStyleClass().add("clear");

but the style will stay the same as class selected

Senna answered 4/6, 2012 at 20:0 Comment(1)
There were some bugs around style class management in some JavaFX versions. Retry your test in a late developer preview and see if you still have issues.Mcdermott
L
16

This is a bug. It is reported here Removal of hovered style class, does not update styling. You may want to vote and watch it. As a workaround you should override css rules you touched/changed to be the same as default ones. Demo:

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBoxBuilder;
import javafx.stage.Stage;

public class StyleDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        final Label lbl = new Label("Style Me");
        lbl.getStyleClass().add("style1"); // initial style

        Button btn = new Button("Change the style");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent arg0) {
                lbl.getStyleClass().remove("style1");
                lbl.getStyleClass().add("style2");
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(VBoxBuilder.create().spacing(20).children(lbl, btn).build());
        Scene scene = new Scene(root, 300, 250);
        scene.getStylesheets().add(this.getClass().getResource("style.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

and the style.css is:

.style1 {
    -fx-text-fill: red;
    -fx-border-color: green;
    -fx-font-size: 20;
}

.style2 {
    -fx-text-fill: blue;
    -fx-border-color: red;
    -fx-font-size: 15;
    -fx-underline: true;
}

when the button is clicked the initially added style1 is removed and the style2 is added.

Layette answered 11/6, 2012 at 8:43 Comment(3)
It's not the best solution because I have to rewrite all the rules to change them, they won't reset automatically to default or other class. But it works. ThanksSenna
No you have not to rewrite. Because style selectors are applied one after another in the order they appear. For example if I removed the style1 and do not added the style2 on button click, then the label remains with its default style defined in built-in caspian.css.Layette
Forget my previous comment. I do now get the point you meant.Layette
R
1

Thanks for the solution posted by Uluk Biy. But it seems not work "as is" (tested on jdk 1.70_40 win x 64). I have to clear style class before settings class. Here the working code for me:

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBoxBuilder;
import javafx.stage.Stage;

public class StyleDemo extends Application {
    //ADD just a toggle property
    public static BooleanProperty toggle = new SimpleBooleanProperty(false);

    @Override
    public void start(Stage primaryStage) {
        final Label lbl = new Label("Style Me");
        lbl.getStyleClass().add("style1"); // initial style

        Button btn = new Button("Change the style");

        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                //ADD clear style class !
                lbl.getStyleClass().clear();
                if(toggle.get()) {
                    lbl.getStyleClass().add("style1");
                    toggle.set(!toggle.get());
                }else{
                    lbl.getStyleClass().add("style2");
                    toggle.set(!toggle.get());
                }
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(VBoxBuilder.create().spacing(20).children(lbl,btn).build());
        Scene scene = new Scene(root, 300, 250); 
        scene.getStylesheets().add("/style.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
Rampart answered 6/10, 2013 at 9:26 Comment(0)
D
1

At least for Java 8, this works now. But instead of doing what the OP did, I would achieve the same like this:

admin_category_label.getStyleClass().remove("selected");
admin_category_label.getStyleClass().add("clear");

Looks a bit cleaner.

Remember, that your CSS selectors need to look like this:

.selected {
    /* Styling attributes... */
}

.clear {
    /* Styling attributes... */
}
Dumond answered 11/9, 2016 at 9:7 Comment(0)
E
1

6 Years laters the bug is still there, here is a simpler way to go, specially if you won't want to mess with the other classes :

int indexOf = textField.getStyleClass().indexOf(INVALID_CLASS);
if(indexOf != -1){
    textField.getStyleClass().remove(indexOf);
}

Why this works ? Because the list used for StyleClass which is a TrackableObservablieList inherits from a hierarchy where the remove(index) does fire changes where the remove(Object) does not.

Ezzell answered 5/2, 2018 at 13:5 Comment(0)
M
0

You can try to add a css for the application instead. You can use even FXML to separate de design from the logic of your application. Here is a piece of code that worked for me in JavaFX 2.1!

private Parent replaceSceneContent(String fxml) throws Exception {
   Parent page = (Parent)
      FXMLLoader.load(
         Main.class.getResource(fxml), null, new JavaFXBuilderFactory());
   Scene scene = stage.getScene();
   if (scene == null) {
      scene = new Scene(page, 1366, 720);
      scene.getStylesheets().add(
         Main.class.getResource(
            "../skinFolder/css/defaultSkin.css" ).toExternalForm());
      stage.setScene(scene);
   } else {
      stage.getScene().setRoot(page);
   }
   stage.sizeToScene();
   return page;
}
Masry answered 10/6, 2012 at 19:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.