1

因此,经过近两个星期的尝试来解决我的问题后,我现在决定制作自己的JavaFX组件。

这个想法是创建一个与现有图表(如折线图和条形图)相连的表格。

由于我对JavaFX(我已经进行了大约 1 个月左右)还很陌生,所以在开始这样的项目之前,我有几个问题:

首先,它可以做到吗?在回答之前,我想向您展示我的目标的示例:

在此处输入图像描述

这张图片取自 Java 插件,JFreeChart在 x 轴上有一个连接表。

我的目标不一定是图表和表格必须 100% 连接,如图所示,但是非常重要的是,每个点/条等下方都有一个带有数据信息的连接表格。

具有连接表的条形图示例如下图所示:

在此处输入图像描述

既然我已经有了图表(内置图表JavaFX),你们认为这会有多难的工作?还有可能吗?

我也很想听听你们是否对如何创建此组件或如何实际创建组件有任何建议。

4

1 回答 1

5

这是一个示例解决方案,炸药在上,鸭子在下。

带表格的折线图

import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.chart.*;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.*;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.Callback;

// http://stackoverflow.com/questions/13337062/creating-my-own-connected-chart-table-javafx
public class TabulatedLineChartWithLegend extends Application {
  private final static String MONTHS[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    
  @Override public void start(Stage stage) {
    stage.setTitle("Line Chart With Attached Tabulated Data");

    final CategoryAxis xAxis = new CategoryAxis();
    xAxis.setTickLength(0);
    final NumberAxis yAxis = new NumberAxis();

    final LineChart<String, Number> lineChart = new LineChart(xAxis, yAxis);
    lineChart.setStyle("-fx-padding: 0;");
    lineChart.setLegendVisible(false);
    lineChart.setTitle("Stock Monitoring, 2010");
    lineChart.getData().addAll(createSeries("ACME Explosives"), createSeries("DUCK Rubber Ducks"));
 
    VBox vbox = new VBox(5);
    vbox.getChildren().addAll(lineChart, createTableView(lineChart));
    vbox.setAlignment(Pos.TOP_LEFT);
    vbox.setMinWidth(500);
    VBox.setMargin(lineChart, new Insets(0,0,0,114));
    
    HBox layout = new HBox();
    layout.getChildren().add(vbox);
    HBox.setHgrow(vbox, Priority.ALWAYS);
    
    Scene scene = new Scene(layout, 700, 500);
    stage.setScene(scene);
    stage.show();
  }
  
  private Series createSeries(String name) {
    XYChart.Series series = new XYChart.Series();
    series.setName(name);
    final ObservableList data = series.getData();
    final DataGenerator generator = new DataGenerator();
    for (String month: MONTHS) {
      data.add(generator.createDataItem(month));
    }
    
    return series;
  }
  
  private TableView createTableView(final LineChart<String, Number> chart) {
    TableView<XYChart.Series<String,Number>> table = new TableView();
    
    if (!chart.getData().isEmpty()) {
      TableColumn legendCol = new TableColumn("Legend");
      legendCol.setResizable(false);
      legendCol.setCellValueFactory(
        new Callback<CellDataFeatures<XYChart.Series<String,Number>, String>, ObservableValue<XYChart.Series<String,Number>>>() {
          @Override public ObservableValue<Series<String, Number>> call(CellDataFeatures<Series<String, Number>, String> param) {
            return new SimpleObjectProperty(param.getValue());
          }
        }  
      );
      legendCol.setCellFactory(new Callback<TableColumn<XYChart.Series<String,Number>,Series<String, Number>>,TableCell<XYChart.Series<String,Number>,Series<String, Number>>>() {
        @Override public TableCell<Series<String, Number>, Series<String, Number>> call(TableColumn<Series<String, Number>, Series<String, Number>> param) {
          return new TableCell<Series<String, Number>, Series<String, Number>>() {
            @Override protected void updateItem(Series<String, Number> series, boolean empty) {
              super.updateItem(series, empty);
              if (series != null) {
                setText(series.getName());
                setGraphic(createSymbol(series, chart.getData().indexOf(series)));
              }  
            }
          };
        }
      });
      table.getColumns().add(legendCol);

      final ObservableList<Data<String, Number>> firstSeriesData = chart.getData().get(0).getData();
      for (final Data<String, Number> item: firstSeriesData) {
        TableColumn col = new TableColumn(item.getXValue());
        col.setSortable(false);
        col.setResizable(false);
        col.prefWidthProperty().bind(chart.getXAxis().widthProperty().divide(firstSeriesData.size()));
        col.setCellValueFactory(
          new Callback<CellDataFeatures<XYChart.Series<String,Number>, String>, ObservableValue<Number>>() {
            @Override public ObservableValue<Number> call(CellDataFeatures<XYChart.Series<String,Number>, String> param) {
              for (Data<String, Number> curItem: param.getValue().getData()) {
                if (curItem.getXValue().equals(item.getXValue())) {
                  return curItem.YValueProperty();
                }
              }
              
              return null;
            }
          }  
        );
        table.getColumns().add(col);
      }
      
      for (XYChart.Series<String,Number> series: chart.getData()) {
        table.getItems().add(series);
      }  

      table.setEditable(false);
      table.setFocusTraversable(false);
    }  
    
    table.setTranslateY(-30);
    table.setPrefHeight(88);
    table.setStyle("-fx-box-border: transparent; -fx-focus-color: transparent; -fx-padding: 0 9 0 9;");
    
    return table;
  }
  
  private Node createSymbol(Series<String, Number> series, int seriesIndex) {
    Node symbol = new StackPane();
    symbol.getStyleClass().setAll(
      "chart-line-symbol", 
      "series" + seriesIndex,
      "default-color" + (seriesIndex % 8)
    );
    return symbol;
  }  
 
  public static void main(String[] args) { launch(args); }
}

// generates random chart data.
class DataGenerator {
  private static final Random random = new Random();
  private int delta = 0;
  private int trend = random.nextInt(4) - 1;
  public Data createDataItem(String month) {
    return new XYChart.Data(month, genDataVal());
  }
  private int genDataVal() {
    delta += trend;
    return random.nextInt(20) + 15 + delta;
  }
}
于 2012-11-15T23:00:37.713 回答