Created
January 27, 2016 23:50
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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