JavaFX table- how to add components and relate them to other scene? - javafx

Is there any way --by clicking on the embedded button -- to open a new scene that is related to the tableview raw selected :
for example :
public class TestClass extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("A", "B", "email#example.com","info"),
new Person("X", "Y", "email2#example.com","info"),
new Person("Z", "W", "email2#example.com","info")
);
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public void start(Stage stage) {
stage.setTitle("Table View Sample");
final Label label = new Label("Address Book");
label.setFont(new Font("Arial", 20));
final Label actionTaken = new Label();
table.setEditable(true);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
TableColumn emailCol = new TableColumn("Email");
emailCol.setMinWidth(200);
emailCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("email"));
TableColumn<Person, Person> btnCol = new TableColumn<>("info");
btnCol.setMinWidth(150);
btnCol.setCellValueFactory(new Callback<CellDataFeatures<Person, Person>, ObservableValue<Person>>() {
#Override public ObservableValue<Person> call(CellDataFeatures<Person, Person> features) {
return new ReadOnlyObjectWrapper(features.getValue());
}
});
btnCol.setComparator(new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.getLikes().compareTo(p2.getLikes());
}
});
btnCol.setCellFactory(new Callback<TableColumn<Person, Person>, TableCell<Person, Person>>() {
#Override public TableCell<Person, Person> call(TableColumn<Person, Person> btnCol) {
Stage stage = null;
return new AddCell(stage, table);
}
});
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, emailCol, btnCol);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 10, 10, 10));
vbox.getChildren().addAll(label, table, actionTaken);
VBox.setVgrow(table, Priority.ALWAYS);
stage.setScene(new Scene(vbox));
stage.show();
}
}
the Person Class :
public class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private final SimpleStringProperty infos;
private Person(String fName, String lName, String email, String infos) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.email = new SimpleStringProperty(email);
this.infos = new SimpleStringProperty(infos);
}
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 String getLikes() {
return infos.get();
}
public void setLikes(String likes) {
this.infos.set(likes);
}
}
}
the AddCell class :
public class AddCell extends TableCell<Person, Boolean> {
final Button addButton = new Button("Elément");
final StackPane paddedButton = new StackPane();
final DoubleProperty buttonY = new SimpleDoubleProperty();
private MessageCmiService messageService=new MessageCmiServiceImpl();
public AddCell(final Stage stage, final TableView table) {
paddedButton.setPadding(new Insets(3));
paddedButton.getChildren().add(addButton);
addButton.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
buttonY.set(mouseEvent.getScreenY());
}
});
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent actionEvent) {
//???
// get the info
}
});
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
}
else{
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(paddedButton);
}
}
}

In your handler, you can do
Person currentPerson = getTableView().getItems().get(getIndex());
which gives you access to all the data in the current row.

Related

TableView is data is not shown in JavaFX

I am using TableView in JavaFX but tableview does not show any data here is my code.
public static class person {
private final SimpleIntegerProperty SR;
private final SimpleStringProperty URL;private person(int sr1,String url1 ){
this.SR=new SimpleIntegerProperty(sr1);
this.URL=new SimpleStringProperty(url1);
}
public int getsr() {
return SR.get();
}
public void setsr(int sr1) {
this.SR.set(sr1);
}
public String geturl() {
return URL.get();
}
public void seturl(String url2) {
this.URL.set(url2);
}
}
public TableView<person> table; TableColumn firstNameCol = new TableColumn("First Name");
TableColumn lastNameCol = new TableColumn("Last Name");
private final ObservableList<person> data1 =
FXCollections.observableArrayList(
new person((int)1, "Smith"),
new person((int)2, "Johnson"),
new person((int)3, "Williams"),
new person((int)4, "Jones"),
new person((int)5, "Brown")
);
public void btnScrapping(ActionEvent event) {
table.setEditable(true);
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<person,Integer>("SR"));
lastNameCol.setMinWidth(500);
lastNameCol.setCellValueFactory(new PropertyValueFactory<person,String>("URL"));
table.setItems(data1);
table.getColumns().addAll(firstNameCol, lastNameCol);
}

javafx adding all subtotal of all column in tableview

I have Tableview here that allows me to multiply the price and the quantity and put that into the subtotal column my question is i want to get the sum of all the subtotals for all the items in the table , thanks
private TableView<Product> table = new TableView<Product>();
private final ObservableList<Product> data =
FXCollections.observableArrayList(
new Product("Notebook", 10, 12),
new Product("Eraser", 20, 12),
new Product("Pencil", 30, 12),
new Product("Pen", 40, 12),
new Product("Glue", 50, 12));
final HBox hb = new HBox();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Book Store Sample");
stage.setWidth(650);
stage.setHeight(550);
final Label label = new Label("Book Store");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
TableColumn name = new TableColumn("Name");
name.setMinWidth(100);
name.setCellValueFactory(
new PropertyValueFactory<Product, String>("name"));
name.setCellFactory(TextFieldTableCell.forTableColumn());
name.setOnEditCommit(
new EventHandler<CellEditEvent<Product, String>>() {
#Override
public void handle(CellEditEvent<Product, String> t) {
((Product) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setName(t.getNewValue());
}
}
);
TableColumn priceCol = new TableColumn("Price");
priceCol.setMinWidth(100);
priceCol.setCellValueFactory(
new PropertyValueFactory<Product, String>("price"));
priceCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter()));
priceCol.setOnEditCommit(
new EventHandler<CellEditEvent<Product, Number>>() {
#Override
public void handle(CellEditEvent<Product, Number> t) {
((Product) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setPrice(t.getNewValue().intValue());
}
}
);
TableColumn quantityCol = new TableColumn("Quantity");
quantityCol.setMinWidth(200);
quantityCol.setCellValueFactory(
new PropertyValueFactory<Product, Number>("quantity"));
quantityCol.setCellFactory(TextFieldTableCell.<Product, Number>forTableColumn(new NumberStringConverter()));
quantityCol.setOnEditCommit(
new EventHandler<CellEditEvent<Product, Number>>() {
#Override
public void handle(CellEditEvent<Product, Number> t) {
((Product) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setQuantity(t.getNewValue().intValue());
}
}
);
TableColumn subTotalCol = new TableColumn("Sub Total");
subTotalCol.setMinWidth(200);
subTotalCol.setCellValueFactory(
new PropertyValueFactory<Product, String>("subTotal"));
table.setItems(data);
table.getColumns().addAll(name, priceCol, quantityCol, subTotalCol);
final TextField addName = new TextField();
addName.setPromptText("Name");
addName.setMaxWidth(name.getPrefWidth());
final TextField addPrice = new TextField();
addPrice.setMaxWidth(priceCol.getPrefWidth());
addPrice.setPromptText("Price");
final TextField addQuantity = new TextField();
addQuantity.setMaxWidth(quantityCol.getPrefWidth());
addQuantity.setPromptText("Quantity");
final Button addButton = new Button("Add");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
data.add(new Product(
name.getText(),
Integer.parseInt(addPrice.getText()),
Integer.parseInt(addQuantity.getText())));
addName.clear();
addPrice.clear();
addQuantity.clear();
}
});
hb.getChildren().addAll(addName, addPrice, addQuantity, addButton);
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();
}
public static class Product {
private final SimpleStringProperty name;
private final SimpleIntegerProperty price;
private final SimpleIntegerProperty quantity;
private final SimpleIntegerProperty subTotal;
private Product(String name, int price, int quantity) {
this.name = new SimpleStringProperty(name);
this.price = new SimpleIntegerProperty(price);
this.quantity = new SimpleIntegerProperty(quantity);
this.subTotal = new SimpleIntegerProperty();
NumberBinding multiplication = Bindings.multiply(this.priceProperty(), this.quantityProperty());
this.subTotalProperty().bind(multiplication);
}
public String getName() {
return name.get();
}
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public int getPrice() {
return price.get();
}
public SimpleIntegerProperty priceProperty() {
return price;
}
public void setPrice(int price) {
this.price.set(price);
}
public int getQuantity() {
return quantity.get();
}
public SimpleIntegerProperty quantityProperty() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity.set(quantity);
}
public int getSubTotal() {
return subTotal.get();
}
public SimpleIntegerProperty subTotalProperty() {
return subTotal;
}
public void setSubTotal(int subTotal) {
this.subTotal.set(subTotal);
}
}
}
You can create a binding that tracks the total of all the subtotal values:
IntegerBinding total = Bindings.createIntegerBinding(() ->
table.getItems().stream().collect(Collectors.summingInt(Product::getSubTotal)),
table.getItems());
The first parameter to this is a function that computes the total of the results of calling product.getSubTotal() on each element in table.getItems(). The second argument ensures that this binding is marked as invalid (so can be recomputed) any time table.getItems() is invalidated.
Using the default mechanism of constructing a list, as you do with ObservableList<Product> data = FXCollections.observableArrayList(...), the list will only be invalidated when items are added, removed, or replaced, but not if the subTotal of an existing item changes. To make this happen, you need to modify that line to use a extractor:
private final ObservableList<Product> data = FXCollections.observableList(Arrays.asList(
new Product("Notebook", 10, 12),
new Product("Eraser", 20, 12),
new Product("Pencil", 30, 12),
new Product("Pen", 40, 12),
new Product("Glue", 50, 12)),
product -> new Observable[] {product.subTotalProperty()});
Now you can do something like
Label totalLabel = new Label();
totalLabel.textProperty().bind(Bindings.format("Total: %d", total));
Update
Here is what the IntegerBinding code looks like without a lambda expression, though it is far less clear and I don't recommend doing this:
IntegerBinding total = Bindings.createIntegerBinding(new Callable<Integer>() {
#Override
public Integer call() {
return table.getItems().stream().collect(Collectors.summingInt(
new ToIntFunction<Product>() {
#Override
public int applyAsInt(Product product) {
return product.getSubTotal();
}
}));
}
}, table.getItems());

Javafx Editable Table cell

I have tables with editable fields firstName,lastName and fullName.
I am creating a cellFactory and Column like this
public class SampleFX1 extends Application {
private TableView table = new TableView();
private final ObservableList<Person> data =
FXCollections.observableArrayList( new Person("balu", "Smith","1"), new Person("Isabella", "john","1"),
new Person("Ethan", "Williams","1"), new Person("Emma", "Jones","1"), new Person("Michael", "Brown","1"));
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
TableColumn firstNameCol = createSimpleFirstNameColumn();
TableColumn lastNameCol = createLastNameColumn();
TableColumn fullNameCol = createfullNameColumn();
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol,fullNameCol);
table.setEditable(true);
((Group) scene.getRoot()).getChildren().addAll(table);
stage.setScene(scene);
stage.show();
}
private TableColumn createSimpleFirstNameColumn() {
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
t.getRowValue().setFirstName(t.getNewValue());
}
});
return firstNameCol;
}
private TableColumn createLastNameColumn() {
Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(editableFactory);
lastNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
System.out.println( "Commiting last name change. Previous: " + t.getOldValue() + " New: " + t.getNewValue() );
t.getRowValue().setLastName(t.getNewValue());
}
});
return lastNameCol;
}
private TableColumn createfullNameColumn() {
TableColumn firstNameCol = new TableColumn("full Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("fullName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
t.getRowValue().setfullName(t.getNewValue());
}
});
return firstNameCol;
}
}
Editing Cell :
public class EditingCell extends TableCell<Person, String> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
super.startEdit();
if( textField == null ) {
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()); }
}
});
textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
String value = textField.getText();
if (value != null) { commitEdit(value); } else { commitEdit(null); }
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
Person Class:
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty firstName;
private SimpleStringProperty lastName;
private SimpleStringProperty fullName;
public Person(String firstName, String lastName ,String fullName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.fullName=new SimpleStringProperty(fullName);
}
public String getFirstName() { return firstName.get(); }
public void setFirstName(String firstName) { this.firstName.set(firstName); }
public SimpleStringProperty firstNameProperty() { return firstName; }
public String getLastName() { return lastName.get(); }
public void setLastName(String lastName) { this.lastName.set(lastName); }
public SimpleStringProperty lastNameProperty() { return lastName; }
public String getfullName() { return fullName.get(); }
public void setfullName(String lastName) { this.fullName.set(lastName); }
public SimpleStringProperty fullNameProperty() { return fullName; }
}
Question: How to Update fullName Column when I update firstName Column or Lastname Column (editable cells) without insert a row?
Use binding to derive the full name from first name and the last name.
fullName.bind(Bindings.concat(this.firstName, " ", this.lastName));
Person.java
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private SimpleStringProperty firstName;
private SimpleStringProperty lastName;
private ReadOnlyStringWrapper fullName = new ReadOnlyStringWrapper();
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
fullName.bind(Bindings.concat(this.firstName, " ", this.lastName));
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public SimpleStringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public SimpleStringProperty lastNameProperty() {
return lastName;
}
public String getFullName() {
return fullName.get();
}
public ReadOnlyStringProperty fullNameProperty() {
return fullName.getReadOnlyProperty();
}
}
Redefine your createfullNameColumn() function. Now that fullName that it is a derived value from concatenating the firstName and the lastName, there is no need to allow a user to explicitly edit it.
private TableColumn createfullNameColumn() {
TableColumn fullNameCol = new TableColumn("Full Name");
fullNameCol.setMinWidth(100);
fullNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("fullName"));
return fullNameCol;
}
SampleFX1.java
Application code:
import javafx.application.Application;
import javafx.collections.*;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.cell.*;
import javafx.stage.Stage;
import javafx.util.Callback;
public class SampleFX1 extends Application {
private TableView table = new TableView();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("balu", "Smith"),
new Person("Isabella", "john"),
new Person("Ethan", "Williams"),
new Person("Emma", "Jones"),
new Person("Michael", "Brown")
);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
TableColumn firstNameCol = createSimpleFirstNameColumn();
TableColumn lastNameCol = createLastNameColumn();
TableColumn fullNameCol = createFullNameColumn();
table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol, fullNameCol);
table.setEditable(true);
((Group) scene.getRoot()).getChildren().addAll(table);
stage.setScene(scene);
stage.show();
}
private TableColumn createSimpleFirstNameColumn() {
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setCellFactory(TextFieldTableCell.forTableColumn());
firstNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
t.getRowValue().setFirstName(t.getNewValue());
}
});
return firstNameCol;
}
private TableColumn createLastNameColumn() {
Callback<TableColumn, TableCell> editableFactory = new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setCellFactory(editableFactory);
lastNameCol.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(TableColumn.CellEditEvent<Person, String> t) {
System.out.println("Commiting last name change. Previous: " + t.getOldValue() + " New: " + t.getNewValue());
t.getRowValue().setLastName(t.getNewValue());
}
});
return lastNameCol;
}
private TableColumn createFullNameColumn() {
TableColumn fullNameCol = new TableColumn("Full Name");
fullNameCol.setMinWidth(100);
fullNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("fullName"));
return fullNameCol;
}
}
EditingCell.java
(unchanged from question)
Update to answer additional user questions on the sample code
I was able to run createSimpleFirstNameColumn() even though there are plenty of warnings from eclipse, for example: TableColumn is a raw type. References to generic type TableColumn should be parameterized.
Original source code was adapted from the standard JavaFX TableView sample code, which at the time wasn't the best example of working with Generics. Generic type specification in Java is optional, but if you mix use an API which has generics specified, but don't supply the generic type information in the API usage, the compiler will issue warnings such as above. In general the warnings can be ignored or if you wish, though you do get a bit nicer type inference and compile time type checking if you explicitly specify type information.
Rather than just saying:
TableColumn firstNameCol = new TableColumn("First Name");
Warnings can be eliminated by explicitly specifying type information such as below:
TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
I have updated the sample code above to use this notation in the createSimpleFirstNameColumn() function.
Note the above code uses a Java 7 diamond notation, so the minimum language compilation level of the program must be set to at least Java 7.
However, in createLastNameColumn() the line with return new EditingCell();gives me an error that EditingCell cannot be resolved to a type.
I do not get this error. You probably have not included the EditingCell class defined in the original question in your project.
I am unable to leave a comment but in answer to this revised question :
I was able to run createSimpleFirstNameColumn() even though there are plenty of warnings from eclipse, for example: TableColumn is a raw type. References to generic type TableColumn should be parameterized.
Make sure that you have the correct import i.e.
import javafx.scene.control.TableColumn; and not anything from Java Swing.

Automatically create TableView columns based on data class info

I have this editable JavaFX table for editing data:
public class DataTable {
public void initTable(Stage primaryStage, Group root, Scene scene) {
tableView.setEditable(true);
Callback<TableColumn, TableCell> cellFactory =
new Callback<TableColumn, TableCell>() {
#Override
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn columnMonth = new TableColumn("Month");
columnMonth.setCellValueFactory(
new PropertyValueFactory<Record, String>("fieldMonth"));
TableColumn columnValue = new TableColumn("Value");
columnValue.setCellValueFactory(
new PropertyValueFactory<Record, Double>("fieldValue"));
//--- Add for Editable Cell of Value field, in Double
columnValue.setCellFactory(cellFactory);
columnValue.setOnEditCommit(
new EventHandler<TableColumn.CellEditEvent<Record, Double>>() {
#Override
public void handle(TableColumn.CellEditEvent<Record, Double> t) {
((Record) t.getTableView().getItems().get(
t.getTablePosition().getRow())).setFieldValue(t.getNewValue());
}
});
//---
tableView.setItems(dataList);
tableView.getColumns().addAll(columnMonth, columnValue);
VBox vBox = new VBox();
vBox.setSpacing(10);
vBox.getChildren().add(tableView);
vBox.setLayoutX(410);
vBox.setLayoutY(34);
root.getChildren().add(vBox);
}
public class Record {
private SimpleStringProperty fieldMonth;
private SimpleDoubleProperty fieldValue;
Record(String fMonth, double fValue) {
this.fieldMonth = new SimpleStringProperty(fMonth);
this.fieldValue = new SimpleDoubleProperty(fValue);
}
public String getFieldMonth() {
return fieldMonth.get();
}
public double getFieldValue() {
return fieldValue.get();
}
public void setFieldMonth(String fMonth) {
fieldMonth.set(fMonth);
}
public void setFieldValue(Double fValue) {
fieldValue.set(fValue);
}
}
private TableView<Record> tableView = new TableView<>();
private ObservableList<Record> dataList =
FXCollections.observableArrayList(
new Record("January", 100),
new Record("February", 200),
new Record("March", 50),
new Record("April", 75),
new Record("May", 110),
new Record("June", 300),
new Record("July", 111),
new Record("August", 30),
new Record("September", 75),
new Record("October", 55),
new Record("November", 225),
new Record("December", 99));
class EditingCell extends TableCell<Record, Double> {
private TextField textField;
public EditingCell() {
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.selectAll();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent t) {
if (t.getCode() == KeyCode.ENTER) {
commitEdit(Double.parseDouble(textField.getText()));
} else if (t.getCode() == KeyCode.ESCAPE) {
cancelEdit();
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
}
I have to create small program which can display data from database tables and edit the tables. I came to this problem when I click on a table I have to generate dynamic table view from JPA object, so I have every time one table but with different columns. Can I somehow generate every time table with the data from JPA and update columns automatically based on the case?
You can use Reflection to achieve that. For example, parse methods of your data class and create column for each one which ends with Property:
public class SmartTableView extends Application {
private void populateColumns(Class clazz, TableView table) {
for (Method method : clazz.getMethods()) {
String name = method.getName();
if (name.endsWith("Property")) {
String propName = name.replace("Property", "");
TableColumn column = new TableColumn(propName);
column.setCellValueFactory(new PropertyValueFactory<>(propName));
table.getColumns().add(column);
}
}
}
#Override
public void start(Stage primaryStage) {
final ObservableList<Person> data = FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Dow", "isabella.dow#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com"));
TableView table = new TableView(data);
populateColumns(Person.class, table);
Scene scene = new Scene(table, 300, 250);
primaryStage.setTitle("Hello");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
private Person(String fName, String lName, String email) {
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 StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String fName) {
lastName.set(fName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
public StringProperty emailProperty() {
return lastName;
}
}
}

editable table in javafx

I'm trying to build a billing system in javafx, and I could build the table and everything. Now I want to change it, I want the table to be already editable, i.e the text fields in the table should be enabled to edit before onEditCommite. Also storing the data in the table is also giving a problem.
The code is given below. In the below code, the rows are being added and can be deleted. But I want to make it editable when the "new bill" button in clicked. Also any method to calculate the Price by multiplying the this.rate and this.qty.
public class abc extends Application {
private TableView<Billing> table = new TableView<Billing>();
private final ObservableList<Billing> data = FXCollections.observableArrayList();
final HBox hb = new HBox();
final HBox hb1=new HBox();
final HBox hb2= new HBox();
private IntegerProperty index = new SimpleIntegerProperty();
public static void main(String[] args) {
launch(args); }
// Stage Start method. Whole Stage.
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Billing");
stage.setWidth(550);
stage.setHeight(650);
final Label label = new Label("Billing Trial 2 ");
label.setFont(new Font("Comic Sans", 26));
//Call EditingCell and set true to make it editable
table.setEditable(true);
Callback<TableColumn, TableCell> cellFactory =
new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
TableColumn srnoCol = new TableColumn("Sr. No. ");
srnoCol.setMinWidth(50);
srnoCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("srNo"));
srnoCol.setCellFactory(cellFactory);
TableColumn numCol = new TableColumn("Item Code ");
numCol.setMinWidth(50);
numCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("itemCode"));
numCol.setCellFactory(cellFactory);
numCol.setOnEditCommit(
new EventHandler<CellEditEvent<Billing, String>>() {
#Override
public void handle(CellEditEvent<Billing, String> t) {
((Billing) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemCode(t.getNewValue());
}
}
);
TableColumn nameCol = new TableColumn("Item Name ");
nameCol.setMinWidth(100);
nameCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("itemName"));
nameCol.setCellFactory(cellFactory);
nameCol.setOnEditCommit(
new EventHandler<CellEditEvent<Billing, String>>() {
#Override
public void handle(CellEditEvent<Billing, String> t) {
((Billing) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemName(t.getNewValue());
}
}
);
TableColumn qtyCol = new TableColumn("Qty ");
qtyCol.setMinWidth(100);
qtyCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("itemQty"));
qtyCol.setCellFactory(cellFactory);
qtyCol.setOnEditCommit(
new EventHandler<CellEditEvent<Billing, String>>() {
#Override
public void handle(CellEditEvent<Billing, String> t) {
((Billing) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemQty(t.getNewValue());
}
}
);
TableColumn rateCol = new TableColumn("Item Rate ");
rateCol.setMinWidth(50);
rateCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("itemRate"));
rateCol.setCellFactory(cellFactory);
rateCol.setOnEditCommit(
new EventHandler<CellEditEvent<Billing, String>>() {
#Override
public void handle(CellEditEvent<Billing, String> t) {
((Billing) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemRate(t.getNewValue());
}
}
);
TableColumn priceCol = new TableColumn("Item Price ");
priceCol.setMinWidth(50);
priceCol.setCellValueFactory(
new PropertyValueFactory<Billing, String>("itemPrice"));
priceCol.setCellFactory(cellFactory);
priceCol.setOnEditCommit(
new EventHandler<CellEditEvent<Billing, String>>() {
#Override
public void handle(CellEditEvent<Billing, String> t) {
((Billing) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setItemPrice(t.getNewValue());
}
}
);
table.setItems(data);
//indexing of elements for deleting function.
table.getSelectionModel().selectedItemProperty().addListener(newChangeListener<Object>() {
#Override
public void changed(ObservableValue<?>observable, Object oldvalue, Object newValue){
index.set(data.indexOf(newValue));
System.out.println("index: "+data.indexOf(newValue));
}
});
//Deleting
final Button deleteButton=new Button("Delete");
deleteButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent de){
int i = index.get();
if (i>-1){
data.remove(i);
table.getSelectionModel().clearSelection();
}
}
});
TableColumn amount = new TableColumn("Amount");
amount.getColumns().addAll(rateCol, priceCol);
table.setItems(data);
table.getColumns().addAll(srnoCol, numCol, nameCol, qtyCol, amount );
//add bill
final Button addButton = new Button("New Bill");
addButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent ae)
{
EditingCell ec = new EditingCell();
ec.getString();
ec.createTextField();
table.setEditable(true);
Callback<TableColumn, TableCell> cellFactory =
new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
return new EditingCell();
}
};
ec.startEdit();
ec.cancelEdit();
data.add(new Billing(null,null,null,null,null,null));
}
});
hb.getChildren().addAll( addButton, deleteButton);
hb.setAlignment(Pos.BASELINE_LEFT);
hb.setSpacing(16);
final Label label2 = new Label();
label2.setAlignment(Pos.BASELINE_RIGHT);
final VBox vbox = new VBox();
vbox.setSpacing(15);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label,hb2, hb, table,hb1);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
//Class Billing
public static class Billing {
private final SimpleStringProperty itemSrNo;
private final SimpleStringProperty itemCode;
private final SimpleStringProperty itemName;
private final SimpleStringProperty itemQty;
private final SimpleStringProperty itemRate;
private final SimpleStringProperty itemPrice;
private Billing(String iSrNo, String iCode, String iName, String iQty, String iRate,String iPrice)
{
this.itemSrNo = new SimpleStringProperty(iSrNo);
this.itemCode = new SimpleStringProperty(iCode);
this.itemName = new SimpleStringProperty(iName);
this.itemPrice = new SimpleStringProperty(iPrice);
this.itemQty = new SimpleStringProperty(iQty);
this.itemRate = new SimpleStringProperty(iRate);
}
public String getItemSrNo() {
return itemSrNo.get();
}
public void setItemSrNo(String iSrNo) {
itemSrNo.set(iSrNo);
}
public String getItemCode() {
return itemCode.get();
}
public void setItemCode(String iCode) {
itemCode.set(iCode);
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String iName) {
itemName.set(iName);
}
public String getItemQty() {
return itemQty.get();
}
public void setItemQty(String iQty) {
itemQty.set(iQty);
}
public String getItemPrice() {
return itemPrice.get();
}
public void setItemPrice(String iPrice) {
itemPrice.set(iPrice);
}
public String getItemRate() {
return itemRate.get();
}
public void setItemRate(String iRate) {
itemRate.set(iRate);
}
}
//CellEditing
public class EditingCell extends TableCell<Billing, 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();
}
}
}
// calculation of Qty x Rate.
class Calculate {
public String sum(int iQty, int iRate)
{
int sum = iQty*iRate;
String s =""+sum;
return s;
}
}
Old question but here is what I think should work : Dont use setGraphic(null) in your cellFactory. Always set it to TextField. Also for the calculation part you can add listeners to your properties in the data model and perform calculation on any change of values for those properties.

Resources