在 JavaFX 中创建分层数据并将其添加到 TreeTableView
Creating hierarchical data and adding it to a TreeTableView in JavaFX
我刚开始编程,我正在 java 中编写一个程序,用于使用单一可转移投票来计算选票。我的输入数据在 Excel 文件中,如下所示:
其中候选人的姓名映射到 HashTable
下方的数字,第 2 行下方的每一行从左到右代表一个选民的偏好。
我想在 TreeTableView
中添加名字和投票,看起来像这样:
.
每个候选人都是他们第二个偏好的根,每个第二个偏好是第三个偏好的根,每个第三个偏好是第四个偏好的根,依此类推。
我正在使用 apache.poi
库来使用 Excel 文件。我正在寻找有关如何表示 sheet 中的分层数据以及如何将其添加到 TreeTabeView
的技巧。我怎么能这样做?
抱歉,如果这是一个菜鸟问题。我不太熟悉如何使用分层数据。提前致谢!
使用具有 2 个属性的项目class
- 候选人
- 投票数
就可以了(=每列一个 属性)。例如
public class VoteEntry {
// candidate INDEX
private final IntegerProperty candidate;
private final IntegerProperty voteCount;
public VoteEntry(int candidate, int count) {
this.voteCount = new SimpleIntegerProperty(count);
this.candidate = new SimpleIntegerProperty(candidate);
}
public final int getCandidate() {
return this.candidate.get();
}
public final void setCandidate(int value) {
this.candidate.set(value);
}
public final IntegerProperty candidateProperty() {
return this.candidate;
}
public final int getVoteCount() {
return this.voteCount.get();
}
public final void setVoteCount(int value) {
this.voteCount.set(value);
}
public final IntegerProperty voteCountProperty() {
return this.voteCount;
}
}
您可以将投票分成越来越小的子组以创建 TreeItem
层次结构:
private final List<int[]> votes = new ArrayList<>();
private void addVote(int... preferences) {
// convert to array of candidate indices sorted descendingly by preference
int[] votes = new int[preferences.length];
for (int i = 0; i < preferences.length; i++) {
votes[preferences[i] - 1] = i;
}
this.votes.add(votes);
}
private static void createHierarchy(TreeItem<VoteEntry> parent, List<int[]> votes, int index) {
int max = votes.stream().mapToInt(a -> a.length).max().getAsInt();
if (max > index) {
// group by candidate
Map<Integer, List<int[]>> groups = votes.stream().collect(Collectors.groupingBy(a -> a.length > index ? a[index] : -1));
groups.forEach((candidate, vts) -> {
if (candidate != -1) {
VoteEntry entry = new VoteEntry(candidate, vts.size());
TreeItem<VoteEntry> item = new TreeItem<>(entry);
parent.getChildren().add(item);
createHierarchy(item, vts, index + 1);
}
});
// sort by candidate
parent.getChildren().sort(Comparator.comparingInt(ti -> ti.getValue().getCandidate()));
}
}
@Override
public void start(Stage primaryStage) {
addVote(1, 2, 3, 4);
addVote(4, 3, 2, 1);
addVote(1, 3, 2, 4);
addVote(2, 1, 4, 3);
addVote(2, 4, 3, 1);
addVote(2, 1, 3, 4);
// ...
ObservableList<String> candidateNames = FXCollections.observableArrayList(
"Candidate 1",
"Candidate 2",
"Candidate 3",
"Candidate 4"
);
TreeItem<VoteEntry> root = new TreeItem<>();
createHierarchy(root, votes, 0);
TreeTableView<VoteEntry> view = new TreeTableView<>(root);
view.setShowRoot(false);
TreeTableColumn<VoteEntry, String> candidateColumn = new TreeTableColumn<>("candidate");
candidateColumn.setCellValueFactory(data -> Bindings.valueAt(candidateNames, data.getValue().getValue().candidateProperty()));
TreeTableColumn<VoteEntry, Integer> votesColumn = new TreeTableColumn<>("votes");
votesColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("voteCount"));
view.getColumns().addAll(candidateColumn, votesColumn);
Scene scene = new Scene(view);
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,递归方法仅适用于有限数量的候选人(Whosebugs)。但它应该适用于合理的候选数量(用户不想扩展数百个项目......)。
我刚开始编程,我正在 java 中编写一个程序,用于使用单一可转移投票来计算选票。我的输入数据在 Excel 文件中,如下所示:
其中候选人的姓名映射到 HashTable
下方的数字,第 2 行下方的每一行从左到右代表一个选民的偏好。
我想在 TreeTableView
中添加名字和投票,看起来像这样:
每个候选人都是他们第二个偏好的根,每个第二个偏好是第三个偏好的根,每个第三个偏好是第四个偏好的根,依此类推。
我正在使用 apache.poi
库来使用 Excel 文件。我正在寻找有关如何表示 sheet 中的分层数据以及如何将其添加到 TreeTabeView
的技巧。我怎么能这样做?
抱歉,如果这是一个菜鸟问题。我不太熟悉如何使用分层数据。提前致谢!
使用具有 2 个属性的项目class
- 候选人
- 投票数
就可以了(=每列一个 属性)。例如
public class VoteEntry {
// candidate INDEX
private final IntegerProperty candidate;
private final IntegerProperty voteCount;
public VoteEntry(int candidate, int count) {
this.voteCount = new SimpleIntegerProperty(count);
this.candidate = new SimpleIntegerProperty(candidate);
}
public final int getCandidate() {
return this.candidate.get();
}
public final void setCandidate(int value) {
this.candidate.set(value);
}
public final IntegerProperty candidateProperty() {
return this.candidate;
}
public final int getVoteCount() {
return this.voteCount.get();
}
public final void setVoteCount(int value) {
this.voteCount.set(value);
}
public final IntegerProperty voteCountProperty() {
return this.voteCount;
}
}
您可以将投票分成越来越小的子组以创建 TreeItem
层次结构:
private final List<int[]> votes = new ArrayList<>();
private void addVote(int... preferences) {
// convert to array of candidate indices sorted descendingly by preference
int[] votes = new int[preferences.length];
for (int i = 0; i < preferences.length; i++) {
votes[preferences[i] - 1] = i;
}
this.votes.add(votes);
}
private static void createHierarchy(TreeItem<VoteEntry> parent, List<int[]> votes, int index) {
int max = votes.stream().mapToInt(a -> a.length).max().getAsInt();
if (max > index) {
// group by candidate
Map<Integer, List<int[]>> groups = votes.stream().collect(Collectors.groupingBy(a -> a.length > index ? a[index] : -1));
groups.forEach((candidate, vts) -> {
if (candidate != -1) {
VoteEntry entry = new VoteEntry(candidate, vts.size());
TreeItem<VoteEntry> item = new TreeItem<>(entry);
parent.getChildren().add(item);
createHierarchy(item, vts, index + 1);
}
});
// sort by candidate
parent.getChildren().sort(Comparator.comparingInt(ti -> ti.getValue().getCandidate()));
}
}
@Override
public void start(Stage primaryStage) {
addVote(1, 2, 3, 4);
addVote(4, 3, 2, 1);
addVote(1, 3, 2, 4);
addVote(2, 1, 4, 3);
addVote(2, 4, 3, 1);
addVote(2, 1, 3, 4);
// ...
ObservableList<String> candidateNames = FXCollections.observableArrayList(
"Candidate 1",
"Candidate 2",
"Candidate 3",
"Candidate 4"
);
TreeItem<VoteEntry> root = new TreeItem<>();
createHierarchy(root, votes, 0);
TreeTableView<VoteEntry> view = new TreeTableView<>(root);
view.setShowRoot(false);
TreeTableColumn<VoteEntry, String> candidateColumn = new TreeTableColumn<>("candidate");
candidateColumn.setCellValueFactory(data -> Bindings.valueAt(candidateNames, data.getValue().getValue().candidateProperty()));
TreeTableColumn<VoteEntry, Integer> votesColumn = new TreeTableColumn<>("votes");
votesColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("voteCount"));
view.getColumns().addAll(candidateColumn, votesColumn);
Scene scene = new Scene(view);
primaryStage.setScene(scene);
primaryStage.show();
}
请注意,递归方法仅适用于有限数量的候选人(Whosebugs)。但它应该适用于合理的候选数量(用户不想扩展数百个项目......)。