I have figured out how to create a TableView
and how to add content to it but I am confused as to how to edit existing content.
In this app I have set it up so a person can add player names and certain stats to the tableview but I want to now be able to add a random roll and add the dex and other modifiers to it and populate the tableview with it. This would reside in the rollInitBtnClicked()
module.
Please help me understand what I need to do.
This is my Main
class.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.control.Button;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
TextField playerName;
TextField dexMod;
TextField otherMod;
TableView<Players> playersTable;
Button addPlayerBtn;
Button rollInitBtn;
Button delPlayerBtn;
public static void main(String[] args){
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Initiative");
// TextField so the user can enter a players Name
playerName = new TextField();
playerName.setPrefSize(200, 20);
playerName.setPromptText("Player Name");
//playerName.setFocusTraversable(false);
// TextField so the user can enter the players dex mod
dexMod = new TextField();
dexMod.setPrefSize(50, 20);
dexMod.setPromptText("Dex");
//dexMod.setFocusTraversable(false);
// TextField so the user can enter the players other mods
otherMod = new TextField();
otherMod.setPrefSize(50, 20);
otherMod.setPromptText("Other");
//otherMod.setFocusTraversable(false);
addPlayerBtn = new Button("Add Player");
addPlayerBtn.setOnAction(e -> addPlayerBtnClicked());
delPlayerBtn = new Button("Delete Player");
delPlayerBtn.setOnAction(e -> delPlayerBtnClicked());
rollInitBtn = new Button("Roll Initiative");
rollInitBtn.setOnAction(e -> rollInitBtnClicked());
//TableView Name Columns
TableColumn<Players, String> nameColumn = new TableColumn<>("Name");
nameColumn.setMinWidth(200);
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
//TableView dexMod Columns
TableColumn<Players, String> dexColumn = new TableColumn<>("Dex Mod");
dexColumn.setMinWidth(50);
dexColumn.setStyle( "-fx-alignment: CENTER;");
dexColumn.setCellValueFactory(new PropertyValueFactory<>("dexMod"));
//TableView otherMod Columns
TableColumn<Players, String> otherColumn = new TableColumn<>("Other Mods");
otherColumn.setMinWidth(50);
otherColumn.setStyle( "-fx-alignment: CENTER;");
otherColumn.setCellValueFactory(new PropertyValueFactory<>("otherMod"));
//TableView roll Columns
TableColumn<Players, String> rollColumn = new TableColumn<>("Die Roll");
rollColumn.setMinWidth(50);
rollColumn.setStyle( "-fx-alignment: CENTER;");
rollColumn.setCellValueFactory(new PropertyValueFactory<>("roll"));
//TableView total Columns
TableColumn<Players, String> totalColumn = new TableColumn<>("Total");
totalColumn.setMinWidth(50);
totalColumn.setStyle( "-fx-alignment: CENTER;");
totalColumn.setCellValueFactory(new PropertyValueFactory<>("total"));
playersTable = new TableView<>();
playersTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
playersTable.setItems(getPlayers());
playersTable.getColumns().addAll(nameColumn, dexColumn, otherColumn, rollColumn, totalColumn);
HBox hLayout = new HBox();
hLayout.setPadding(new Insets(10, 10, 10, 10)); // sets the padding on the top right left and bottom of the layout
hLayout.setSpacing(10); // sets the spacing between the TextFields and buttons
hLayout.getChildren().addAll(playerName, dexMod, otherMod, addPlayerBtn, rollInitBtn, delPlayerBtn);
VBox vLayout = new VBox();
vLayout.getChildren().addAll(playersTable, hLayout);
Scene mainScene = new Scene(vLayout, 800, 400);
primaryStage.setScene(mainScene);
primaryStage.show();
}
// What happens when the user clicks the Add Player button
public void addPlayerBtnClicked() {
Players players = new Players();
players.setName(playerName.getText());
players.setDexMod(Integer.parseInt(dexMod.getText()));
players.setOtherMod(Integer.parseInt(otherMod.getText()));
playersTable.getItems().add(players);
playerName.clear();
dexMod.clear();
otherMod.clear();
}
// What happens when the user clicks the Delete Player button
public void delPlayerBtnClicked() {
ObservableList<Players> playerSelected, allPlayers;
allPlayers = playersTable.getItems();
playerSelected = playersTable.getSelectionModel().getSelectedItems();
playerSelected.forEach(allPlayers::remove);
}
public void rollInitBtnClicked() {
Players players = new Players();
ObservableList<Players> playerSelected, allPlayers;
allPlayers = playersTable.getItems();
playerSelected = playersTable.getSelectionModel().getSelectedItems();
players.setRoll((int)Math.ceil(Math.random() * 20));
}
public ObservableList<Players> getPlayers(){
ObservableList<Players> players = FXCollections.observableArrayList();
return players;
}
}
The following lives in a class named Players
.
public class Players {
private String name;
private int dexMod;
private int otherMod;
private int roll;
private int total;
// default method to enter default data
public Players(){
}
// overloaded method to enter data that is handed to it
public Players(String name, int dexMod, int otherMod, int roll, int total){
this.name = name;
this.dexMod = dexMod;
this.otherMod = otherMod;
this.roll = roll;
this.total = total;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDexMod() {
return dexMod;
}
public void setDexMod(int dexMod) {
this.dexMod = dexMod;
}
public int getOtherMod() {
return otherMod;
}
public void setOtherMod(int otherMod) {
this.otherMod = otherMod;
}
public int getRoll() {
return roll;
}
public void setRoll(int roll) {
this.roll = roll;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
}
You firstly need to mark the table as editable
playersTable.setEditable(true);
Also you need to change the cell factory for any editable columns.
nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
for the integer type columns, you'll also need to specify a converter.
otherColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
rollColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
totalColumn.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
and fix the declaration from <Players, String>
to <Players, Integer>
, ie
TableColumn<Players, Integer> totalColumn = new TableColumn<>("Total");
You should now be able to edit the table by either doing a "long click", or pressing F2, ie just like standard applications...
More information can be found in the official tutorial
For the TableView
to be notified of modifications, you need to make a ObservableValue
wrapping the property value available that is notified of modifications. PropertyValueFactory
uses a method <propertyName>Property()
to retrieve this ObservableValue
. If no such method exists, it uses the getter; However in this case the TableView
not notified of any modification. Furthermore the total
property should not be modifiable on it's own.
Starting with JavaFX 8u60 there is a refresh
method in TableView
, which would allow you to manually trigger a refresh:
private final Random random = new Random();
public void rollInitBtnClicked() {
List<Players> targets = playersTable.getItems();
for (Players p : targets) {
p.setRoll(random.nextInt(20));
// set total ect...
}
// update table
playersTable.refresh();
}
However the "standard approach that is also compatible with older versions of JavaFX would be modifying the properties:
private final IntegerProperty roll = new SimpleIntegerProperty();
public int getRoll() {
return roll.get();
}
public void setRoll(int roll) {
this.roll.set(roll);
}
public IntegerProperty rollProperty() {
return this.roll;
}
// same modifications for other int properties
...
private final IntegerBinding total = Bindings.createIntegerBinding(() -> getRoll() + getOtherMod() + getDexMod(), roll, otherMod, dexMod);
public int getTotal() {
return this.total.get();
}
public IntegerBinding totalProperty() {
return this.total;
}
This would allow you to remove the refresh
call from the rollInitBtnClicked
method posted above.
Players
, but Player
. You're using incorrect type parameters for your TableColumn
s. This is not important here, since PropertyValueFactory
works regardless of type parameters, but it could get you into problems, if you use other features of TableColumn
. The second type parameter should always match the type parameter of the ObservableValue
returned by the cellValueFactory
:
TableColumn<Players, String> nameColumn TableColumn<Players, Number> dexColumn TableColumn<Players, Number> otherColumn TableColumn<Players, Number> rollColumn TableColumn<Players, Number> totalColumn
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.