5 Replies Latest reply: Nov 7, 2012 2:14 PM by David Grieve RSS

    Creating a table within the actual Chart

    972913
      Hello i'm trying to create a connected table to my line chart.

      The chart shows information for each day: Monday, tuesday, wednesday (ect ect).

      Under each day (point) i want to show information for that day in a table.

      is this possible ? and if so how?
        • 1. Re: Creating a table within the actual Chart
          jsmith
          Well FWIW, here's my attempt.
          The tables render strange and the CSS handling is unfathomable and spits out copious warnings when run (perhaps David Grieve knows why).
          But anyway, maybe it will help you.
          Or somebody else may have a better idea - perhaps using the node.lookupAll function on the Graph or some other means.
          import javafx.application.Application;
          import javafx.collections.FXCollections;
          import javafx.scene.*;
          import javafx.scene.chart.LineChart;
          import javafx.scene.chart.NumberAxis;
          import javafx.scene.chart.XYChart;
          import javafx.scene.chart.XYChart.Data;
          import javafx.scene.control.*;
          import javafx.scene.control.cell.PropertyValueFactory;
          import javafx.stage.Stage;
          
          public class LineChartWithTables extends Application {
            @Override public void start(Stage stage) {
              stage.setTitle("Line Chart Sample");
              //defining the axes
              final NumberAxis xAxis = new NumberAxis();
              final NumberAxis yAxis = new NumberAxis();
              xAxis.setLabel("Number of Month");
              //creating the chart
              final LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
          
              lineChart.setTitle("Stock Monitoring, 2010");
              //defining a series
              XYChart.Series series = new XYChart.Series();
              series.setName("My portfolio");
              //populating the series with data
              series.getData().add(createData(1, 23));
              series.getData().add(createData(2, 14));
              series.getData().add(createData(3, 15));
              series.getData().add(createData(4, 24));
              series.getData().add(createData(5, 34));
              series.getData().add(createData(6, 36));
              series.getData().add(createData(7, 22));
              series.getData().add(createData(8, 45));
              series.getData().add(createData(9, 43));
              series.getData().add(createData(10, 17));
              series.getData().add(createData(11, 29));
              series.getData().add(createData(12, 25));
          
              Scene scene = new Scene(lineChart, 800, 600);
              lineChart.getData().add(series);
          
              stage.setScene(scene);
              stage.show();
            }
          
            private Data createData(int x, int y) {
              Data data = new XYChart.Data(x, y);
              data.setNode(createTableView(data));
              
              return data;
            }
          
            private TableView createTableView(Data data) {
              TableView<Data> table = new TableView<>();
              TableColumn xCol = new TableColumn("X");
              xCol.setCellValueFactory(new PropertyValueFactory("XValue"));
              TableColumn yCol = new TableColumn("Y");
              yCol.setCellValueFactory(new PropertyValueFactory("YValue"));
              
              table.getColumns().setAll(xCol, yCol);
              table.setItems(FXCollections.observableArrayList(data));
              table.setStyle("-fx-skin: \"com.sun.javafx.scene.control.skin.TableViewSkin\"; -fx-background-color: #f9d900, aliceblue;"); // no idea why this line with the TableViewSkin is needed and it doesn't fix css issues with the table anyway. . .
              table.setPrefSize(65, 55);
          
              return table;
            }
            
            public static void main(String[] args) { launch(args); }
          }
          • 2. Re: Creating a table within the actual Chart
            972913
            First of all THANK you for your hard work however this wasnt exactly what i ment :)

            all i want is basicly the information displayed under the graph you know where it says "my portfolio" instead of having that simply have a table view that gives information!
            • 3. Re: Creating a table within the actual Chart
              David Grieve
              First of all, I think John's chart with tables a nodes is pretty cool. The reason the CSS errors are being logged and the reason he had to add the style with -fx-skin is that the node in the chart (the TableView) isn't part of the scene graph in the same way that other nodes are. Normally, if you followed the parent chain of a node in the scene, you'd get to a parent with a "root" style class. But the TableView in this code is not a descendant of the "root" node. Rather, it is an element in the ObservableList. A quick fix is to add the style "-fx-table-cell-border-color: aliceblue;" to the inline style on the TableView. Adding the style class "root" to the TableView should also work, but I didn't try that.

              Here's John's code again with a TableView below the chart. Notice that the chart and the TableView use the same data, which is what I think you are after.
              import javafx.application.Application;
              import javafx.collections.FXCollections;
              import javafx.collections.ObservableList;
              import javafx.scene.*;
              import javafx.scene.chart.LineChart;
              import javafx.scene.chart.NumberAxis;
              import javafx.scene.chart.XYChart;
              import javafx.scene.chart.XYChart.Data;
              import javafx.scene.control.*;
              import javafx.scene.control.cell.PropertyValueFactory;
              import javafx.scene.layout.VBox;
              import javafx.stage.Stage;
               
              public class Main extends Application {
                  
                @Override public void start(Stage stage) {
                  stage.setTitle("Line Chart Sample");
                  //defining the axes
                  final NumberAxis xAxis = new NumberAxis();
                  final NumberAxis yAxis = new NumberAxis();
                  xAxis.setLabel("Number of Month");
                  //creating the chart
                  final LineChart<Number, Number> lineChart = new LineChart(xAxis, yAxis);
               
                  lineChart.setTitle("Stock Monitoring, 2010");
                  //defining a series
                  XYChart.Series series = new XYChart.Series();
                  series.setName("My portfolio");
                  //populating the series with data
                  series.getData().add(createData(1, 23));
                  series.getData().add(createData(2, 14));
                  series.getData().add(createData(3, 15));
                  series.getData().add(createData(4, 24));
                  series.getData().add(createData(5, 34));
                  series.getData().add(createData(6, 36));
                  series.getData().add(createData(7, 22));
                  series.getData().add(createData(8, 45));
                  series.getData().add(createData(9, 43));
                  series.getData().add(createData(10, 17));
                  series.getData().add(createData(11, 29));
                  series.getData().add(createData(12, 25));
               
                  VBox vbox = new VBox(5);
                  vbox.getChildren().addAll(lineChart, createTableView(series.getData()));
                  
                  Scene scene = new Scene(vbox, 800, 600);
              //    Scene scene = new Scene(lineChart, 800, 600);
                  lineChart.getData().add(series);
               
                  stage.setScene(scene);
                  stage.show();
                }
               
                private Data createData(int x, int y) {
                  Data data = new XYChart.Data(x, y);
              //    data.setNode(createTableView(data));
                  
                  return data;
                }
               
              //  private TableView createTableView(Data data) {
                private TableView createTableView(ObservableList data) {//Data data) {
                  TableView<Data> table = new TableView();
                  TableColumn xCol = new TableColumn("X");
                  xCol.setCellValueFactory(new PropertyValueFactory("XValue"));
                  TableColumn yCol = new TableColumn("Y");
                  yCol.setCellValueFactory(new PropertyValueFactory("YValue"));
                  
                  table.getColumns().setAll(xCol, yCol);
              //    table.setItems(FXCollections.observableArrayList(data));
                  table.setItems(data);
              //    table.setStyle("-fx-skin: \"com.sun.javafx.scene.control.skin.TableViewSkin\"; -fx-table-cell-border-color: aliceblue; -fx-background-color: #f9d900, aliceblue;"); // no idea why this line with the TableViewSkin is needed and it doesn't fix css issues with the table anyway. . .
              //    table.setPrefSize(65, 55);
               
                  return table;
                }
              
                public static void main(String[] args) { launch(args); }
              }
              • 4. Re: Creating a table within the actual Chart
                jsmith
                Thanks for looking at my code and answering the poster's question David.
                I tried adding the root class to my sample and that didn't work.

                I don't think the issue is do with the tables not being part of a normal scene graph, instead it is because the LineGraph code at various times makes a setAll call on the symbol node's styleClass removing the default styleclass (of "table-view") from the TableView, including any pre-existing styles. Because the default styleclass contains the table-view's skin this causes warnings and rendering differences.

                After I added a style class ChangeListener to my createTableView code and ensured the table-view style was always present, everything rendered as I'd expect without any issue.
                private TableView createTableView(Data data) {
                  final TableView<Data> table = new TableView<>();
                  TableColumn xCol = new TableColumn("X");
                  xCol.setCellValueFactory(new PropertyValueFactory("XValue"));
                  TableColumn yCol = new TableColumn("Y");
                  yCol.setCellValueFactory(new PropertyValueFactory("YValue"));
                    
                  table.getColumns().setAll(xCol, yCol);
                  table.setItems(FXCollections.observableArrayList(data));
                  table.getStyleClass().addListener(new ListChangeListener<String>() {
                    @Override public void onChanged(Change<? extends String> c) {
                      if (!table.getStyleClass().contains("table-view")) {
                        table.getStyleClass().add("table-view");
                      }
                    }
                  });
                    
                  table.setPrefSize(70, 70);
                
                  return table;
                }
                As I don't think the LineChart code should remove the existing styles from the custom symbol nodes, I logged http://javafx-jira.kenai.com/browse/RT-26110 "LineChart removes existing styles from custom symbols"
                • 5. Re: Creating a table within the actual Chart
                  David Grieve
                  Excellent! Good find. Thanks for filing the bug.