Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8089003

StackedBarChart/TableCell chart shown incorrectly

XMLWordPrintable

      Using StackedBarChart as cell graphics in a custom TableCell (or ListCell, didn't try others but suspect it's similar for tree) has weird effects when updating the item, depending on how we do the update:

      - scenario A: initialize the chart with the series and update the data in the series. The bars appear fine only on the very first showing, scrolling back and forth leaves random "gaps" inside
      - scenario B: create and set new series in each round. The bars seem to have the correct width, but their colors changes randomly on scrolling

      To reproduce, see the example below
      - expected is ... well, a nicely drawn stackedBar in the third column, visualizing the relative values of the the first two columns.
      - actual depends on scenario

      for scenario A: compile and run as-is
      - initially, the cells shown on the first page appear as expected
      - scroll up/down: bars have "gaps", that is their drawing seems random, even in the initially correctly painted cells

      for scenario B: comment the initial setting of the series, uncomment the part marked as scenario B
      - initially, the cells shown on the first page appear as expected
      - scroll up/down: the bars are correctly drawn, but randomly changing colors

      This worked as expected in 8u20/25, but not in 8u40b20 so seems to be a regression somewhere (didn't dig whether in stackedBarChart or cell)

      Also discussed at SO, http://stackoverflow.com/q/28152250/203657

      The example:

      import javafx.scene.chart.StackedBarChart;
      import javafx.application.Application;
      import javafx.beans.property.ReadOnlyObjectWrapper;
      import javafx.beans.property.SimpleIntegerProperty;
      import javafx.collections.FXCollections;
      import javafx.collections.ObservableList;
      import javafx.scene.Scene;
      import javafx.scene.chart.CategoryAxis;
      import javafx.scene.chart.NumberAxis;
      import javafx.scene.chart.XYChart;
      import javafx.scene.control.TableCell;
      import javafx.scene.control.TableColumn;
      import javafx.scene.control.TableView;
      import javafx.stage.Stage;

      /**
       * How to show relative bars with colors of
       * a related chart
       *
       * Here trying to use StackedBarChart .. problems as noted in cell doc.
       * Extracted TableStackedBarChart for SO question.
       */
      public class TableStackedBar extends Application {
          public static void main(String[] args) { launch(args); }

          @Override
          public void start(Stage stage) {
              ObservableList<Data> data = FXCollections.observableArrayList();
              for (int i = 0; i<10; i++) data.add(new Data());

              TableView<Data> tv = new TableView<>(data);
              TableColumn<Data, Number> col1 = new TableColumn<>("num1");
              TableColumn<Data, Number> col2 = new TableColumn<>("num2");
              col1.setCellValueFactory((p)->{return p.getValue().num1;});
              col2.setCellValueFactory((p)->{return p.getValue().num2;});

              //make this column hold the entire Data object so we can access all fields
              TableColumn<Data, Data> col3 = new TableColumn<>("bar");
              col3.setPrefWidth(500);
              col3.setCellValueFactory((p)->{return new ReadOnlyObjectWrapper<>(p.getValue());});

              col3.setCellFactory(p -> new StackedBarChartCell(2000.));
              tv.getColumns().addAll(col1,col2,col3);
              tv.setFixedCellSize(50.);
              
              Scene scene = new Scene(tv);

              stage.setScene(scene);
              stage.setTitle(System.getProperty("java.version"));
              stage.show();
          }

          /**
           * TableCell that uses a StackedBarChart to visualize relation of
           * data.
           *
           * Problems with updating items:
           * - scenario A: updating the series leaves empty patches horizontally
           * - scenario B: re-setting the series changes colors randomly
           *
           * Other problems
           * - runs amok without fixedCellSize on tableView
           * - can't max the height of the chart (so it's cut-off in the middle
           */
          public static class StackedBarChartCell extends TableCell<Data, Data> {
              
              NumberAxis xAxisHoriz = new NumberAxis();
              CategoryAxis yAxisHoriz = new CategoryAxis();
              StackedBarChart<Number, String> sbcHoriz = new StackedBarChart<>(xAxisHoriz, yAxisHoriz);
              XYChart.Series<Number, String> series1Horiz = new XYChart.Series<>();
              XYChart.Series<Number, String> series2Horiz = new XYChart.Series<>();
              
              
              public StackedBarChartCell(double upperBound) {
                  yAxisHoriz.setTickLabelsVisible(false);
                  yAxisHoriz.setTickMarkVisible(false);
                  yAxisHoriz.setStyle("-fx-border-color: transparent transparent transparent transparent;");
                  
                  xAxisHoriz.setTickLabelsVisible(false);
                  xAxisHoriz.setTickMarkVisible(false);
                  xAxisHoriz.setMinorTickVisible(false);
                  xAxisHoriz.setStyle("-fx-border-color: transparent transparent transparent transparent;");
                  xAxisHoriz.setAutoRanging(false);
                  xAxisHoriz.setUpperBound(upperBound);
                  xAxisHoriz.setLowerBound(0.);
                  
                  sbcHoriz.setHorizontalGridLinesVisible(false);
                  sbcHoriz.setVerticalGridLinesVisible(false);
                  sbcHoriz.setLegendVisible(false);
                  sbcHoriz.setAnimated(false);
                  
                  // scenario A: set series initially
                  sbcHoriz.getData().setAll(series1Horiz, series2Horiz);
                  sbcHoriz.setCategoryGap(0);
                  // no effect
                  sbcHoriz.setMaxHeight(20);
              }
              @Override
              protected void updateItem(Data item, boolean empty) {
                  super.updateItem(item, empty);
                  if (empty) {
                      setGraphic(null);
                  } else {
                      setGraphic(sbcHoriz);
                      // scenario B: set new series
      // XYChart.Series<Number, String> series1Horiz = new XYChart.Series<>();
      // XYChart.Series<Number, String> series2Horiz = new XYChart.Series<>();
      // sbcHoriz.getData().setAll(series1Horiz, series2Horiz);
                      //---- end of scenario B
                      series1Horiz.getData().setAll(new XYChart.Data(item.num1.get(), "none"));
                      series2Horiz.getData().setAll(new XYChart.Data(item.num2.get(), "none"));
                  }
              }
              
          }
          
          
          private static class Data{
              private SimpleIntegerProperty num1 = new SimpleIntegerProperty((int)(Math.random()*1000));
              private SimpleIntegerProperty num2 = new SimpleIntegerProperty((int)(Math.random()*1000));

              public SimpleIntegerProperty num1Property(){return num1;}
              public SimpleIntegerProperty num2Property(){return num2;}
          }
      }

            Unassigned Unassigned
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Imported: