11 Replies Latest reply: Feb 25, 2013 10:11 AM by David Grieve RSS

    Can't Dynamically Restyle A Node

    mfortner
      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
          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
            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
              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
                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
                  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
                    Hi David
                    this looks like the problem described in Jira : RT-25656
                    • 7. Re: Can't Dynamically Restyle A Node
                      mfortner
                      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
                        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
                          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
                            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
                              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;
                              }