Skip to content

Instantly share code, notes, and snippets.

@james-d
Created January 27, 2016 23:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save james-d/aa51204a2e7ed16d75b7 to your computer and use it in GitHub Desktop.
Save james-d/aa51204a2e7ed16d75b7 to your computer and use it in GitHub Desktop.
Example of table with varying number of columns according to user input
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.beans.binding.ObjectBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ScoreTable extends Application {
private TableView<Game> scoreTable ;
@Override
public void start(Stage primaryStage) {
scoreTable = new TableView<>();
Label placeholder = new Label();
scoreTable.setPlaceholder(placeholder);
placeholder.textProperty().bind(Bindings
.when(Bindings.isEmpty(scoreTable.getColumns()))
.then("No players")
.otherwise("No games"));
scoreTable.setEditable(true);
TextArea playerInput = new TextArea();
playerInput.setPromptText("Enter players (one per line)");
playerInput.setPrefColumnCount(20);
Button reset = new Button("Set players");
reset.disableProperty().bind(playerInput.textProperty().isEmpty());
reset.setOnAction(e -> {
List<String> players =
Stream.of(playerInput.getText().split("\n"))
.collect(Collectors.toList());
resetTable(players);
playerInput.clear();
});
Button newGame = new Button("New Game");
newGame.disableProperty().bind(Bindings.isEmpty(scoreTable.getColumns()));
newGame.setOnAction(e -> scoreTable.getItems()
.add(new Game(scoreTable.getItems().size()+1)));
HBox buttons = new HBox(5, reset, newGame);
VBox controls = new VBox(5, playerInput, buttons);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(scoreTable);
root.setLeft(controls);
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
playerInput.requestFocus();
}
private void resetTable(List<String> players) {
scoreTable.getColumns().clear();
scoreTable.getItems().clear();
TableColumn<Game, Integer> gameNumCol = new TableColumn<>("Game");
gameNumCol.setCellValueFactory(cellData ->
new ObjectBinding<Integer>() {
@Override
public Integer computeValue() {
return cellData.getValue().getGameNumber();
}
});
gameNumCol.setCellFactory(tc -> new TableCell<Game, Integer>() {
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
setText(empty ? null : "Game "+item);
}
});
scoreTable.getColumns().add(gameNumCol);
for (String player : players) {
TableColumn<Game, Integer> col = new TableColumn<>(player);
col.setCellValueFactory(cellData -> {
Game game = cellData.getValue();
IntegerBinding score = Bindings.createIntegerBinding(() ->
game.getScores().getOrDefault(player, 0),
game.getScores());
return score.asObject() ;
});
col.setCellFactory(c -> new IntegerEditingCell());
// if you need editing:
col.setOnEditCommit(e -> {
Game game = e.getRowValue();
Integer newScore = e.getNewValue();
game.getScores().put(player, newScore);
});
col.setPrefWidth(100);
scoreTable.getColumns().add(col);
}
}
private static class IntegerEditingCell extends TableCell<Game, Integer> {
private final TextField textField = new TextField();
IntegerEditingCell() {
textField.setTextFormatter(new TextFormatter<Integer>(change ->
change.getControlNewText().matches("\\d*") ? change : null));
textField.setOnAction(e -> {
if (textField.getText().isEmpty()) {
commitEdit(0);
} else {
commitEdit(Integer.parseInt(textField.getText()));
}
});
textField.addEventFilter(KeyEvent.KEY_RELEASED, e -> {
if (e.getCode()==KeyCode.ESCAPE) {
cancelEdit();
}
});
setGraphic(textField);
}
@Override
protected void updateItem(Integer item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
setContentDisplay(ContentDisplay.TEXT_ONLY);
return ;
}
if (isEditing()) {
textField.setText(item.toString());
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(item.toString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
@Override
public void startEdit() {
super.startEdit();
textField.setText(getItem().toString());
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText(getItem().toString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
public static class Game {
private final int gameNumber ;
private final ObservableMap<String, Integer> scores
= FXCollections.observableHashMap();
public Game(int gameNumber) {
this.gameNumber = gameNumber ;
}
public ObservableMap<String, Integer> getScores() {
return scores ;
}
public int getGameNumber() {
return gameNumber ;
}
}
public static void main(String[] args) {
launch(args);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment