这结合了垃圾神和 James_D 的想法:
具有自定义单元工厂和图形的 TableView,
图形可能只是一个单行网格窗格中的三个适当样式的标签,并设置了列约束。
除此之外,它是一个标准的表格视图实现。
由于四舍五入,我的示例中的数字并不总是等于 100%,因此您可能希望对此做一些事情,如果是这样,我让您自己决定。
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.text.NumberFormat;
import java.util.Arrays;
public class ChartTableApp extends Application {
private final ObservableList<Outcomes> outcomes = FXCollections.observableList(
Arrays.asList(
new Outcomes("Qxd5", 5722, 5722, 3646),
new Outcomes("Kf6", 2727, 2262, 1597),
new Outcomes("c6", 11, 1, 5),
new Outcomes("e6", 0, 1, 1)
)
);
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setScene(new Scene(createOutcomesTableView()));
stage.show();
}
private TableView<Outcomes> createOutcomesTableView() {
final TableView<Outcomes> outcomesTable = new TableView<>(outcomes);
TableColumn<Outcomes, String> moveCol = new TableColumn<>("Move");
moveCol.setCellValueFactory(o ->
new SimpleStringProperty(o.getValue().move())
);
TableColumn<Outcomes, Integer> totalCol = new TableColumn<>("Total");
totalCol.setCellValueFactory(o ->
new SimpleIntegerProperty(o.getValue().total()).asObject()
);
totalCol.setCellFactory(p ->
new IntegerCell()
);
totalCol.setStyle("-fx-alignment: BASELINE_RIGHT;");
TableColumn<Outcomes, Outcomes> outcomesCol = new TableColumn<>("Outcomes");
outcomesCol.setCellValueFactory(o ->
new SimpleObjectProperty<>(o.getValue())
);
outcomesCol.setCellFactory(p ->
new OutcomesCell()
);
//noinspection unchecked
outcomesTable.getColumns().addAll(
moveCol,
totalCol,
outcomesCol
);
outcomesTable.setPrefSize(450, 150);
return outcomesTable;
}
public record Outcomes(String move, int wins, int draws, int losses) {
public int total() { return wins + draws + losses; }
public double winPercent() { return percent(wins); }
public double drawPercent() { return percent(draws); }
public double lossPercent() { return percent(losses); }
private double percent(int value) { return value * 100.0 / total(); }
}
private static class OutcomesCell extends TableCell<Outcomes, Outcomes> {
OutcomesBar bar = new OutcomesBar();
@Override
protected void updateItem(Outcomes item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
bar.setOutcomes(item);
setGraphic(bar);
}
}
}
private static class OutcomesBar extends GridPane {
private final Label winsLabel = new Label();
private final Label drawsLabel = new Label();
private final Label lossesLabel = new Label();
private final ColumnConstraints winsColConstraints = new ColumnConstraints();
private final ColumnConstraints drawsColConstraints = new ColumnConstraints();
private final ColumnConstraints lossesColConstraints = new ColumnConstraints();
public OutcomesBar() {
winsLabel.setStyle("-fx-background-color : lightgray");
drawsLabel.setStyle("-fx-background-color : darkgray");
lossesLabel.setStyle("-fx-background-color : gray");
winsLabel.setAlignment(Pos.CENTER);
drawsLabel.setAlignment(Pos.CENTER);
lossesLabel.setAlignment(Pos.CENTER);
winsLabel.setMaxWidth(Double.MAX_VALUE);
drawsLabel.setMaxWidth(Double.MAX_VALUE);
lossesLabel.setMaxWidth(Double.MAX_VALUE);
addRow(0, winsLabel, drawsLabel, lossesLabel);
getColumnConstraints().addAll(
winsColConstraints,
drawsColConstraints,
lossesColConstraints
);
}
public void setOutcomes(Outcomes outcomes) {
winsLabel.setText((int) outcomes.winPercent() + "%");
drawsLabel.setText((int) outcomes.drawPercent() + "%");
lossesLabel.setText((int) outcomes.lossPercent() + "%");
winsColConstraints.setPercentWidth(outcomes.winPercent());
drawsColConstraints.setPercentWidth(outcomes.drawPercent());
lossesColConstraints.setPercentWidth(outcomes.lossPercent());
}
}
private static class IntegerCell extends TableCell<Outcomes, Integer> {
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(
NumberFormat.getNumberInstance().format(
item
)
);
}
}
}
}