条形图作为 JavaFX 中的 TableRow
Barchart as TableRow in JavaFX
我想使用 JavaFX 将这种条形图添加到我的应用程序中:
本质上:A(可能很大,即最多 50 个条目)table。对于每一行,都有几列包含信息。一条信息是关于 win/draw/loss 比率的百分比,即三个数字 10%、50%、40%。我想用三种不同的颜色以图形方式将这三个百分比显示为垂直条。以便用户可以直观地了解这些百分比。
我还没有找到使用 JavaFX 进行此操作的简单或直接的方法。至少现在似乎无法控制。我也无法从 ControlsFX 中找到似乎 suitable 的控件。我目前正在做的是获取信息本身,以及三列百分比,如下所示:
Option Win Draw Loss
============================
option1 10% 50% 40%
option2 20% 70% 10%
option3 ...
但这不是很好。如何实现上述图形显示?
(添加了一张图片以便更好地理解;它来自 lichess.org 他们在 html 中正是这样做的)
这结合了 trashgod 和 James_D 的想法:
a TableView with a custom cell factory and graphic,
The graphic could just be three appropriately-styled labels in a single-row grid pane with column constraints set.
除此之外,它是一个标准的 table 视图实现。
由于四舍五入,我示例中的数字并不总是相加为 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
)
);
}
}
}
}
我想使用 JavaFX 将这种条形图添加到我的应用程序中:
本质上:A(可能很大,即最多 50 个条目)table。对于每一行,都有几列包含信息。一条信息是关于 win/draw/loss 比率的百分比,即三个数字 10%、50%、40%。我想用三种不同的颜色以图形方式将这三个百分比显示为垂直条。以便用户可以直观地了解这些百分比。
我还没有找到使用 JavaFX 进行此操作的简单或直接的方法。至少现在似乎无法控制。我也无法从 ControlsFX 中找到似乎 suitable 的控件。我目前正在做的是获取信息本身,以及三列百分比,如下所示:
Option Win Draw Loss
============================
option1 10% 50% 40%
option2 20% 70% 10%
option3 ...
但这不是很好。如何实现上述图形显示?
(添加了一张图片以便更好地理解;它来自 lichess.org 他们在 html 中正是这样做的)
这结合了 trashgod 和 James_D 的想法:
a TableView with a custom cell factory and graphic,
The graphic could just be three appropriately-styled labels in a single-row grid pane with column constraints set.
除此之外,它是一个标准的 table 视图实现。
由于四舍五入,我示例中的数字并不总是相加为 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
)
);
}
}
}
}