I have a table, and I create the columns in the following way:
@FXML
TableView<Row> tableView = new TableView<>();
private void createColumns(int numberOfColumns, Row firstRow, boolean errorsDisplayed) {
for (int i = 0; i < numberOfColumns; i++) {
int colNum = i;
TableColumn<Row, String> column = new TableColumn<>(firstRow.getCell(i).toString());
column.setCellValueFactory(param -> {
int index = param.getTableView().getColumns().indexOf(param.getTableColumn());
return new SimpleStringProperty(param.getValue().getLastCellNum() > index
? param.getValue().getCell(index).toString() : null);
});
if (!errorsDisplayed || (colNum != numberOfColumns - 1 && colNum != numberOfColumns - 2)) {
column.setCellFactory(TextFieldTableCell.forTableColumn());
column.setOnEditCommit(param -> param.getTableView().getItems().get(param.getTablePosition()
.getRow()).getCell(colNum).setCellValue(param.getNewValue()));
}
tableView.getColumns().add(column);
}
}
Is there a way I could store different states of the table in order to restore them when the undo button being pressed?
I create an app that can hopefully help. It is probably full of traps and pitfalls so don't attempt to use the code as it. I got the Undo/Redo ideas from here . Two Stack
are used to implement the ideas. I got the code for the TableView
from here . Changes are committed on focus lost.
Main
/*
Altered code from the following!
1. https://docs.oracle.com/javafx/2/ui_controls/table-view.htm
2. https://www.geeksforgeeks.org/implement-undo-and-redo-features-of-a-text-editor/
*/
import com.mycompany.javafxsimpletest.MyAction.MyActionType;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
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.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
public class App extends Application {
final private UndoRedo undoRedo = new UndoRedo();
final private TableView<Person> table = new TableView();
final private HBox hb = new HBox();
private ObservableList<Person> data;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
data = FXCollections.observableArrayList(
new Person(GenerateUniqueId.getUniqueId(), "Jacob", "Smith", "jacob.smith@example.com"),
new Person(GenerateUniqueId.getUniqueId(), "Isabella", "Johnson", "isabella.johnson@example.com"),
new Person(GenerateUniqueId.getUniqueId(), "Ethan", "Williams", "ethan.williams@example.com"),
new Person(GenerateUniqueId.getUniqueId(), "Emma", "Jones", "emma.jones@example.com"),
new Person(GenerateUniqueId.getUniqueId(), "Michael", "Brown", "michael.brown@example.com"));
//Since I added these Persons via code and not manually, I added that action here!
data.forEach((newPerson) -> {
undoRedo.addAction(new MyAction(MyActionType.ADD, null, newPerson.copy()));
System.out.println("Add Undo Action - \n\tActionType: " + MyActionType.ADD + "\n\tOld Person: " + null + "\n\tnew Person: " + newPerson);
});
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(450);
stage.setHeight(550);
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
Callback<TableColumn, TableCell> cellFactory = (TableColumn p) -> new EditingCell();
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(cellFactory);
firstNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
@Override
public void handle(CellEditEvent<Person, String> t) {
Person oldPerson = t.getTableView().getItems().get(t.getTablePosition().getRow());
Person newPerson = oldPerson.copy();
newPerson.setFirstName(t.getNewValue());
undoRedo.addAction(new MyAction(MyActionType.EDIT, oldPerson, newPerson));
System.out.println("Add Undo Action - \n\tActionType: " + MyActionType.EDIT + "\n\tOld Person: " + oldPerson + "\n\tnew Person: " + newPerson);
}
}
);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(cellFactory);
lastNameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
@Override
public void handle(CellEditEvent<Person, String> t) {
Person oldPerson = t.getTableView().getItems().get(t.getTablePosition().getRow());
Person newPerson = oldPerson.copy();
newPerson.setLastName(t.getNewValue());
undoRedo.addAction(new MyAction(MyActionType.EDIT, oldPerson, newPerson));
System.out.println("Add Undo Action - \n\tActionType: " + MyActionType.EDIT + "\n\tOld Person: " + oldPerson + "\n\tnew Person: " + newPerson);
}
}
);
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
emailCol.setCellFactory(cellFactory);
emailCol.setOnEditCommit(
new EventHandler<CellEditEvent<Person, String>>() {
@Override
public void handle(CellEditEvent<Person, String> t) {
Person oldPerson = t.getTableView().getItems().get(t.getTablePosition().getRow());
Person newPerson = oldPerson.copy();
newPerson.setEmail(t.getNewValue());
undoRedo.addAction(new MyAction(MyActionType.EDIT, oldPerson, newPerson));
System.out.println("Add Undo Action - \n\tActionType: " + MyActionType.EDIT + "\n\tOld Person: " + oldPerson + "\n\tnew Person: " + newPerson);
}
}
);
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);
final TextField addFirstName = new TextField();
addFirstName.setPromptText("First Name");
addFirstName.setMaxWidth(firstNameCol.getPrefWidth());
final TextField addLastName = new TextField();
addLastName.setMaxWidth(lastNameCol.getPrefWidth());
addLastName.setPromptText("Last Name");
final TextField addEmail = new TextField();
addEmail.setMaxWidth(emailCol.getPrefWidth());
addEmail.setPromptText("Email");
final Button addButton = new Button("Add");
addButton.setOnAction((ActionEvent e) -> {
Person newPerson = new Person(GenerateUniqueId.getUniqueId(),addFirstName.getText(), addLastName.getText(), addEmail.getText());
data.add(newPerson);
addFirstName.clear();
addLastName.clear();
addEmail.clear();
undoRedo.addAction(new MyAction(MyActionType.ADD, null, newPerson.copy()));
System.out.println("Add Undo Action - ActionType: " + MyActionType.ADD + "\tPerson: " + newPerson);
});
Button btnUndo = new Button("<");
btnUndo.setOnAction((t) -> {
if(!undoRedo.isUndoEmpty())
{
MyAction myUndoAction = undoRedo.getUndo();
Person oldPerson = (Person)myUndoAction.getOldAction();
Person newPerson = (Person)myUndoAction.getNewAction();
System.out.println("Add Undo Action - \n\tActionType: " + myUndoAction.getActionType() + "\n\tOld Person: " + oldPerson + "\n\tnew Person: " + newPerson);
if(myUndoAction.getActionType() == MyActionType.ADD)
{
data.remove(data.indexOf(data.stream().filter((z) -> z.getId() == newPerson.getId()).findFirst().get()));
}
else if(myUndoAction.getActionType() == MyActionType.EDIT)
{
data.set(data.indexOf(data.stream().filter((z) -> z.getId() == oldPerson.getId()).findFirst().get()), oldPerson);
}
}
});
Button btnRedo = new Button(">");
btnRedo.setOnAction((t) -> {
if(!undoRedo.isRedoEmpty())
{
MyAction myRedoAction = undoRedo.getRedo();
Person oldPerson = (Person)myRedoAction.getOldAction();
Person newPerson = (Person)myRedoAction.getNewAction();
System.out.println("Add Undo Action - \n\tActionType: " + myRedoAction.getActionType() + "\n\tOld Person: " + oldPerson + "\n\tnew Person: " + newPerson);
if(myRedoAction.getActionType() == MyActionType.ADD)
{
data.add(newPerson.getId(), newPerson);
}
else if(myRedoAction.getActionType() == MyActionType.EDIT)
{
data.set(data.indexOf(data.stream().filter((z) -> z.getId() == newPerson.getId()).findFirst().get()), newPerson);
}
}
});
hb.getChildren().addAll(addFirstName, addLastName, addEmail, addButton, btnUndo, btnRedo);
hb.setSpacing(3);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table, hb);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
@Override
public void startEdit() {
if (!isEmpty()) {
super.startEdit();
createTextField();
setText(null);
setGraphic(textField);
textField.selectAll();
}
}
@Override
public void cancelEdit() {
super.cancelEdit();
setText((String) getItem());
setGraphic(null);
}
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setText(null);
setGraphic(textField);
} else {
setText(getString());
setGraphic(null);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap()* 2);
textField.focusedProperty().addListener(new ChangeListener<Boolean>(){
@Override
public void changed(ObservableValue<? extends Boolean> arg0,
Boolean arg1, Boolean arg2) {
if (!arg2) {
commitEdit(textField.getText());
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
}
Person
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final IntegerProperty id;
private final StringProperty firstName;
private final StringProperty lastName;
private final StringProperty email;
public Person(int id, String fName, String lName, String email) {
this.id = new SimpleIntegerProperty(id);
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String fName) {
firstName.set(fName);
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
public int getId()
{
return id.get();
}
@Override public String toString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("id: ").append(this.id.get())
.append("\tName:").append(this.firstName.get()).append(" ").append(this.lastName.get())
.append("\temail: ").append(this.email.get());
return stringBuilder.toString();
}
public Person copy()
{
Person copyPerson = new Person(this.id.get(), this.firstName.get(), this.lastName.get(), this.email.get());
return copyPerson;
}
}
MyAction
/**
*
* @author blj0011(sedj601)
* @param <T>
*/
public class MyAction<T>
{
public enum MyActionType {
ADD,
DELETE,
EDIT
}
private final T oldAction;
private final T newAction;
private final MyActionType myActionType;
public MyAction(MyActionType actionType, T oldAction, T newAction) {
this.oldAction = oldAction;
this.newAction = newAction;
this.myActionType = actionType;
}
public T getOldAction()
{
return this.oldAction;
}
public T getNewAction()
{
return this.newAction;
}
public MyActionType getActionType()
{
return this.myActionType;
}
}
UndoRedo
import java.util.Stack;
/**
*
* author 2. https://www.geeksforgeeks.org/implement-undo-and-redo-features-of-a-text-editor/
*
*/
public class UndoRedo {
private final Stack<MyAction> undo = new Stack();
private final Stack<MyAction> redo = new Stack();
public void addAction(MyAction myAction)
{
undo.push(myAction);
}
// Function to perform
// "UNDO" operation
public MyAction getUndo()
{
MyAction myAction = undo.peek();
undo.pop();
redo .push(myAction);
return myAction;
}
// Function to perform
// "REDO" operation
public MyAction getRedo()
{
MyAction myAction = redo.peek();
redo.pop();
undo.push(myAction);
return myAction;
}
//Check if stack is empty before attempting to do use getUndo()!
public boolean isUndoEmpty()
{
return undo.empty();
}
//Check if stack is empty before attempting to do use getRedo()!
public boolean isRedoEmpty()
{
return redo.empty();
}
}
**GenerateUniqueId
/**
*
* @author blj0011(sedj601)
*/
public class GenerateUniqueId {
static AtomicInteger uniqueIdGenerator = new AtomicInteger();
public static int getUniqueId()
{
return uniqueIdGenerator.getAndIncrement();
}
}
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.