This discussion is archived
11 Replies Latest reply: Feb 25, 2013 8:11 AM by David Grieve RSS

Can't Dynamically Restyle A Node

mfortner Newbie
Currently Being Moderated
I have a node that needs conditional styling. I have a stylesheet that contains a *.selected-style* and a *.unselected-style* definition. The node has a additional styles already applied to it, and I need to turn one of these styles on/off depending on some condition. I can't directly set the style, because that overrides any other styles already applied to the node. So I'm trying to add/remove a style class from the nodes styleclass list. Here's what I'm trying:
String SELECTED_STYLE = "selected-style";
String UNSELECTED_STYLE = "unselected-style";
if (isSelected){
  node.getStyleClass().remove(UNSELECTED_STYLE);
  node.getStyleClass().add(SELECTED_STYLE);
} else{
  node.getStyleClass().add(UNSELECTED_STYLE);
  node.getStyleClass().remove(SELECTED_STYLE);
}
But this doesn't work. Is there any other way to do this?
  • 1. Re: Can't Dynamically Restyle A Node
    David Grieve Pro
    Currently Being Moderated
    This should work. What does the .css file look like? Do you have code that reproduces that you can share here? What version of javafx?
  • 2. Re: Can't Dynamically Restyle A Node
    956927 Newbie
    Currently Being Moderated
    Hy there,

    as i had the same problem i got it to work in my project with clearing the StyleClass,
    should work on yours too:

    String SELECTED_STYLE = "selected-style";
    String UNSELECTED_STYLE = "unselected-style";
    if (isSelected){
    node.getStyleClass().clear();
    node.getStyleClass().add(SELECTED_STYLE);
    } else{
    node.getStyleClass().clear();
    node.getStyleClass().add(UNSELECTED_STYLE);
    }


    BR
    Harry
  • 3. Re: Can't Dynamically Restyle A Node
    mfortner Newbie
    Currently Being Moderated
    Hi Harry,
    That definitely an idea. But in my estimation the style classes should be treated as a set that the user can add/remove from, and any changes made to that set should be automatically reflected in the node.

    I'll give your approach a try and see what happens.

    Thanks,

    Mark
  • 4. Re: Can't Dynamically Restyle A Node
    e-dubkendo Newbie
    Currently Being Moderated
    One of the first things I'd check in this situation is that my conditional was actually getting handled correctly, so if the other idea does not work, you definitely might want to put a println or something inside the if statement to make sure isSelected is actually being evaluated as you think.
  • 5. Re: Can't Dynamically Restyle A Node
    David Grieve Pro
    Currently Being Moderated
    I'm the guy that wrote the code, so it would really help me to help you if you'd tell me what version of javafx you are using and maybe post some sample code.
  • 6. Re: Can't Dynamically Restyle A Node
    127223 Newbie
    Currently Being Moderated
    Hi David
    this looks like the problem described in Jira : RT-25656
  • 7. Re: Can't Dynamically Restyle A Node
    mfortner Newbie
    Currently Being Moderated
    Hi David,
    The sample code that I posted at the beginning is probably the closest I can come to giving you a non-proprietary example. I'm using that snippet to turn on/off styles applied to a series in a LineChart.

    I used the suggestion to clear the styleClass Observable list, and that did the trick. The new code looks something like this:
                    Set<String> styleSet = new HashSet<String>(line.getStyleClass());
                    
                    line.getStyleClass().clear();
    
                    if (selected) {
                        styleSet.remove(BAR_NORMAL);
                        styleSet.add(BAR_SELECTED);
                        
                        log.debug("Highlighted: " + dataItem.getXValue());
                    } else {
                        styleSet.add(BAR_NORMAL);
                        styleSet.remove(BAR_SELECTED);
                        log.debug("Normal: " + dataItem.getXValue());
                    }
                    
                    line.getStyleClass().addAll(styleSet);
    It would be nice if the setStyle and getStyleClass().add() methods worked together. So that setting a style, did not clear any default styling already being applied to the node.

    Edited by: mfortner on Feb 19, 2013 10:06 AM

    Edited by: mfortner on Feb 19, 2013 10:21 AM
  • 8. Re: Can't Dynamically Restyle A Node
    mfortner Newbie
    Currently Being Moderated
    As the politicians say, "I misspoke". I retested this and it's still not working. I've tried calling layout or layoutPlotChildren after changing the styling on the series's line node. Nothing seems to work. I can change the opacity directly (via line.setOpacity(0.5) without going through the CSS) and that works without any problem. It looks like the problem is that the series's node is ignoring the style changes. The CSS looks like this
    .not-included{
       -fx-stroke-dash-array: 5.0 2.0 5.0 2.0;
    }
    
    .included{
       -fx-stroke-dash-array: 1.0;
    }
  • 9. Re: Can't Dynamically Restyle A Node
    David Grieve Pro
    Currently Being Moderated
    The following code works.
        String SELECTED_STYLE = "selected-style";
        String UNSELECTED_STYLE = "unselected-style";
    
        @Override
        public void start(Stage stage) {
    
            final CheckBox btn = new CheckBox("CheckBox");
            btn.setOnAction(new EventHandler<ActionEvent>(){
    
                @Override
                public void handle(ActionEvent t) {
                    if (btn.isSelected()) {
                        btn.getStyleClass().remove(UNSELECTED_STYLE);
                        btn.getStyleClass().add(SELECTED_STYLE);
                    } else {
                        btn.getStyleClass().remove(SELECTED_STYLE);
                        btn.getStyleClass().add(UNSELECTED_STYLE);
                    }
                    System.out.println(btn.getStyleClass());
                }
            });
            
            AnchorPane root = new AnchorPane();
            root.setPrefSize(200, 200);
            root.getChildren().add(btn);
    
            Scene scene = new Scene(root);
            scene.getStylesheets().add("/fxtest/test.css");
            stage.setScene(scene);
            stage.show();
                    
        }
    // test.css
    .check-box.selected-style { -fx-base: green; }
    .check-box.unselected-style { -fx-base: red; }
  • 10. Re: Can't Dynamically Restyle A Node
    mfortner Newbie
    Currently Being Moderated
    As I said earlier, I think the problem is with the chart's series node (not with re-styling components in general). I have a checkbox that's firing events at the chart, telling it to change the styling of a particular series in the chart. If I tell it to change the opacity (instead of restyling), then the series is updated properly. If I attempt to restyle the series, nothing happens.
  • 11. Re: Can't Dynamically Restyle A Node
    David Grieve Pro
    Currently Being Moderated
    I see no problem with the chart series, either. If you run this code, you can click on the chart legend to cycle through the styles.
        private LineChart<Number,Number> lineChart;
        private String[] styles = new String[] { "unselected-style", "selected-style", "" };
        int n = 0;
        
        @Override public void start(Stage stage) {
            
            final NumberAxis xAxis = new NumberAxis();
            xAxis.setLabel("X Axis");
            
            final NumberAxis yAxis = new NumberAxis();
            yAxis.setLabel("Y Axis");
            
            lineChart = new LineChart<Number,Number>(xAxis,yAxis);
    
            XYChart.Series series = new XYChart.Series();
            series.setName("Series 0");
    
            series.getData().addAll(
                new XYChart.Data(20d, 50d),
                new XYChart.Data(40d, 80d),            
                new XYChart.Data(50d, 90d),            
                new XYChart.Data(70d, 30d),            
                new XYChart.Data(170d, 122d)
            );
                    
    
            lineChart.getData().add(series);
            
            final Scene scene = new Scene(createLineChart(), 500, 500);
            scene.getStylesheets().add("test.css");
            stage.setScene(scene);
            stage.show();
                    
            Node legend = scene.lookup(".chart-legend");
            legend.setOnMouseClicked(new EventHandler<MouseEvent>() {
    
                @Override
                public void handle(MouseEvent t) {
                   Node node = scene.lookup(".chart-series-line.series0");
                   String style = styles[n%styles.length];
                   if (style != null && !style.isEmpty()) {
                       node.getStyleClass().remove(style);
                   }
                   style = styles[++n%styles.length];
                   if (style != null && !style.isEmpty()) {
                       node.getStyleClass().add(style);
                   }
                   System.out.println(node.getStyleClass().toString());
                }
            });
        }
    /* test.css */
    
    .plot-content > .chart-series-line.series0.default-color0 {
        -fx-stroke: green;
    }
    .plot-content > .chart-series-line.series0.default-color0.selected-style {
        -fx-stroke: red;
    }
    .plot-content > .chart-series-line.series0.default-color0.unselected-style {
        -fx-stroke: blue;
    }

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points