I'm trying to learn how TableView work's in JavaFX. I wrote a simple class to add a list of movies to a table but when I run it I'm getting this error:
javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'Price' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory#3aebd1d5 with provided class type: class application.MovieClass
java.lang.IllegalStateException: Cannot read from unreadable property Price
there are 3 variables in the movie class and I get the same error for all of them.
here are the 2 classes that I wrote
main:
package application;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
public class Main extends Application {
TableView<MovieClass> table;
#Override
public void start(Stage primaryStage) {
Label lblHeading = new Label("Movie Inventory");
TableView<MovieClass> table = new TableView<MovieClass>();
table.setItems(loadData());
TableColumn<MovieClass, String> colTitle = new TableColumn<MovieClass, String>("Title");
colTitle.setMinWidth(300);
colTitle.setCellValueFactory(
new PropertyValueFactory<MovieClass, String>("title"));
TableColumn<MovieClass, Integer> colYear = new TableColumn<MovieClass, Integer>("year");
colYear.setMinWidth(100);
colYear.setCellValueFactory(
new PropertyValueFactory<MovieClass, Integer>("Year"));
TableColumn<MovieClass, Double> colPrice = new TableColumn<MovieClass, Double>("price");
colPrice.setMinWidth(100);
colPrice.setCellValueFactory(
new PropertyValueFactory<MovieClass, Double>("Price"));
table.getColumns().addAll(colTitle, colYear, colPrice);
print(loadData());
VBox paneMain = new VBox();
paneMain.setSpacing(10);
paneMain.setPadding(new Insets(10, 10, 10, 10));
paneMain.getChildren().addAll(lblHeading, table);
Scene scene = new Scene(paneMain);
primaryStage.setScene(scene);
primaryStage.setTitle("Movie Inventory");
primaryStage.show();
}
public ObservableList<MovieClass> loadData()
{
ObservableList<MovieClass> data = FXCollections.observableArrayList();
data.add(new MovieClass("It's a Wonderful Life",1946, 14.95));
data.add(new MovieClass("Young Frankenstein",1974, 16.95));
data.add(new MovieClass("Star Wars Episode 4",1976, 17.95));
data.add(new MovieClass("The Princess Bride",1987, 16.95));
data.add(new MovieClass("Glory",1989, 14.95));
data.add(new MovieClass("The Game",1997, 14.95));
data.add(new MovieClass("Shakespeare in Love",1998, 19.95));
data.add(new MovieClass("The Invention of Lying",2009, 18.95));
data.add(new MovieClass("The King's Speech",2010, 19.95));
return data; }
public void print(ObservableList<MovieClass> list) {
for(int i = 0; i > list.size(); i++) {
System.out.println("The Title = " + list.get(i).getMyTitle()
+ " " + "The Year = " + list.get(i).getMyYear()
+ " " + "The Price = " + list.get(i).getMyPrice());
}
}
public static void main(String[] args) {
launch(args);
}
}
movie class:
package application;
public class MovieClass {
private String title;
private int year;
private double price;
public MovieClass()
{
this.title = "";
this.year = 0;
this.price = 0.0;
}
public MovieClass(String title, int year, double price)
{
this.title = title;
this.year = year;
this.price = price;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public int getYear() {
return this.year;
}
public void setYear(int year) {
this.year = year;
}
public double getPrice() {
return this.price;
}
public void setPrice(double price) {
this.price = price;
}
}
Related
In the following code there are 4 columns. In "Particular Value" column different types of data can be added like string, integer, date, etc. But I want to add a button in same column next to value entered in that cell, only if that value is string.
something like this:
First name| Last Name| Age| Particular value
James | Smith | 10 | 10
Jacob | Wisly | 20 | abc (button)
Anna | Samaul | 15 | 45.5
How to do add button in same column only for particular cell i.e containing string value?
package application;
import java.time.LocalDateTime;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
public class Main extends Application {
private final TableView<Person<?>> tableView = new TableView<>();
private Person<Integer> person1 = new Person<>("Jacob", "Smith", 28, 4);
private Person<Integer> person2 = new Person<>("Isabella", "Johnson", 19, 5);
private Person<String> person3 = new Person<>("Bob", "The Sponge", 13, "Say Hi!");
private Person<LocalDateTime> person4 = new Person<>("Time", "Is Money", 45, LocalDateTime.now());
private Person<Double> person5 = new Person<>("John", "Doe", 32, 457.89);
private final ObservableList<Person<?>> data = FXCollections.observableArrayList(person1, person2, person3, person4,
person5);
#SuppressWarnings("unchecked")
#Override
public void start(Stage primaryStage) {
TableColumn<Person<?>, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(new PropertyValueFactory<>("firstName"));
TableColumn<Person<?>, String> lastNameCol = new TableColumn<>("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(new PropertyValueFactory<>("lastName"));
TableColumn<Person<?>, Integer> ageCol = new TableColumn<>("Age");
ageCol.setMinWidth(50);
ageCol.setCellValueFactory(new PropertyValueFactory<>("age"));
TableColumn<Person<?>, ?> particularValueCol = new TableColumn<>("Particular Value");
particularValueCol.setMinWidth(200);
particularValueCol.setCellValueFactory(new PropertyValueFactory<>("particularValue"));
tableView.setItems(data);
// Type safety: A generic array of Table... is created for a varargs
// parameter
// -> #SuppressWarnings("unchecked") to start method!
tableView.getColumns().addAll(firstNameCol, lastNameCol, ageCol, particularValueCol);
// Output in console the selected table view's cell value/class to check
// that the data type is correct.
SystemOutTableViewSelectedCell.set(tableView);
// To check that table view is correctly refreshed on data changed..
final Button agePlusOneButton = new Button("Age +1");
agePlusOneButton.setOnAction((ActionEvent e) -> {
Person<?> person = tableView.getSelectionModel().getSelectedItem();
try {
person.setAge(person.getAge() + 1);
} catch (NullPointerException npe) {
//
}
});
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(tableView, agePlusOneButton);
Scene scene = new Scene(new Group());
((Group) scene.getRoot()).getChildren().addAll(vbox);
primaryStage.setWidth(600);
primaryStage.setHeight(750);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person<T> {
private final StringProperty firstName;
private final StringProperty lastName;
private final IntegerProperty age;
private final ObjectProperty<T> particularValue;
private Person(String firstName, String lastName, Integer age, T particularValue) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.age = new SimpleIntegerProperty(age);
this.particularValue = new SimpleObjectProperty<T>(particularValue);
}
public String getFirstName() {
return firstName.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName;
}
public Integer getAge() {
return age.get();
}
public void setAge(Integer age) {
this.age.set(age);
}
public IntegerProperty ageProperty() {
return age;
}
public T getParticularValue() {
return particularValue.get();
}
public void setParticularValue(T particularValue) {
this.particularValue.set(particularValue);
}
public ObjectProperty<T> particularValueProperty() {
return particularValue;
}
}
public static final class SystemOutTableViewSelectedCell {
#SuppressWarnings({ "rawtypes", "unchecked" })
public static void set(TableView tableView) {
tableView.getSelectionModel().setCellSelectionEnabled(true);
ObservableList selectedCells = tableView.getSelectionModel().getSelectedCells();
selectedCells.addListener(new ListChangeListener() {
#Override
public void onChanged(Change c) {
TablePosition tablePosition = (TablePosition) selectedCells.get(0);
Object val = tablePosition.getTableColumn().getCellData(tablePosition.getRow());
System.out.println("Selected Cell (Row: " + tablePosition.getRow() + " / Col: "
+ tablePosition.getColumn() + ") Value: " + val + " / " + val.getClass());
}
});
}
}
}
You can do:
TableColumn<Person<?>, Object> particularValueCol = new TableColumn<>("Particular Value");
particularValueCol.setMinWidth(200);
particularValueCol.setCellValueFactory(new PropertyValueFactory<>("particularValue"));
particularValueCol.setCellFactory(tc -> new TableCell<Person<?>, Object>() {
private Button button = new Button("A button");
#Override
protected void updateItem(Object item, boolean empty) {
super.updateItem(item, empty) ;
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setText(item.toString());
if (item instanceof String) {
setGraphic(button);
} else {
setGraphic(null);
}
}
}
});
This question already has answers here:
JavaFX Tableview - column value dependent on other columns
(2 answers)
Closed 6 years ago.
I would like to bind amount column to price and quantity columns such that everytime either quantity or price, amount updates.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.converter.NumberStringConverter;
/**
*
* #author Yunus
*/
public class ColumnBinding extends Application{
private TableView<Product> table = new TableView<Product>();
private final ObservableList<Product> data = FXCollections.observableArrayList();
final HBox hb = new HBox();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Scene scene = new Scene(new Group());
primaryStage.setTitle("Book Store Sample");
primaryStage.setWidth(650);
primaryStage.setHeight(550);
final Label label = new Label("Testing");
label.setFont(new Font("Arial", 20));
table.setEditable(true);
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 amount = new TableColumn("Amount");
amount.setMinWidth(200);
amount.setCellValueFactory(
new PropertyValueFactory<Product, String>("amount"));
data.addAll(new Product(10, 12, 120),
new Product(20, 12, 240),
new Product(30, 12, 360),
new Product(40, 12, 480),
new Product(50, 12, 600));
table.setItems(data);
table.getColumns().addAll(priceCol, quantityCol, amount);
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);
primaryStage.setScene(scene);
primaryStage.show();
}
public static class Product{
Product(){}
public Product(float quantity, float price, float amount) {
this.quantity = quantity;
this.price = price;
this.amount = amount;
}
private float quantity;
private float price;
private float amount;
public float getQuantity() {
return quantity;
}
public void setQuantity(float quantity) {
this.quantity = quantity;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public float getAmount() {
return amount;
}
public void setAmount(float amount) {
this.amount = amount;
}
}
}
The challenge though is not to change POJO class(Product) with property fields
I would just use JavaFX properties in the model class. Then you can establish the relationship by binding in the model:
public static class Product{
private final FloatProperty quantity = new SimpleFloatProperty();
private final FloatProperty price = new SimpleFloatProperty();
private final ReadOnlyFloatWrapper amount = new ReadOnlyFloatWrapper();
Product(){
this(0f, 0f);
}
// if amount is supposed to depend on quantity and price, it makes
// no sense at all to have a constructor taking parameters for all
// three values...
public Product(float quantity, float price) {
setQuantity(quantity);
setPrice(price);
this.amount.bind(this.quantity.multiply(this.price));
}
public float getQuantity() {
return quantityProperty().get();
}
public void setQuantity(float quantity) {
quantityProperty().set(quantity);
}
public FloatProperty quantityProperty() {
return quantity ;
}
public float getPrice() {
return priceProperty().get();
}
public void setPrice(float price) {
priceProperty().set(price);
}
public FloatProperty priceProperty() {
return price ;
}
public float getAmount() {
return amountProperty.get();
}
// Again, it makes no sense at all to have this method
// if amount depends on the other values
// public void setAmount(float amount) {
// this.amount = amount;
// }
public ReadOnlyFloatProperty amountProperty() {
return amount.getReadOnlyProperty();
}
}
Now your table columns are easy:
TableColumn<Product, Float> priceColumn = new TableColumn<>("Price");
priceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty().asObject());
TableColumn<Product, Float> quantityColumn = new TableColumn<>("Quantity");
quantityColumn.setCellValueFactory(cellData -> cellData.getValue().quantityProperty().asObject());
TableColumn<Product, Float> amountColumn = new TableColumn<>("Amount");
amountColumn.setCellValueFactory(cellData -> cellData.getValue().amountProperty().asObject());
I'm using a listener to set the height of my Textarea in the TextfieldCellFactory:
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Supermain extends Application {
#Override
public void start(Stage primaryStage) {
final TableView<myTextRow> table = new TableView<>();
table.setEditable(true);
table.setStyle("-fx-text-wrap: true;");
//Table columns
TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory());
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory());
//Add data
final ObservableList<myTextRow> data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem","Test"),
new myTextRow(2, "Ipsum","Test2")
);
table.getColumns().addAll(clmID, clmtext,clmtext2);
table.setItems(data);
HBox hBox = new HBox();
hBox.setSpacing(5.0);
hBox.setPadding(new Insets(5, 5, 5, 5));
Button btn = new Button();
btn.setText("Get Data");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for (myTextRow data1 : data) {
System.out.println("data:" + data1.getText());
}
}
});
hBox.getChildren().add(btn);
BorderPane pane = new BorderPane();
pane.setTop(hBox);
pane.setCenter(table);
primaryStage.setScene(new Scene(pane, 640, 480));
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public static class TextFieldCellFactory
implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell();
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
public TextFieldCell() {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
this.setGraphic(textField);
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// Retrieve the actual String Property that should be bound to the TextField
// If the TextField is currently bound to a different StringProperty
// Unbind the old property and rebind to the new one
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp = (SimpleStringProperty) ov;
if (this.boundToCurrently == null) {
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(sp);
} else if (this.boundToCurrently != sp) {
this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(this.boundToCurrently);
}
double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22);
textField.setPrefHeight(height);
textField.setMaxHeight(height);
// if height bigger than the biggest height in the row
//-> change all heights of the row(textfields ()typeof textarea) to this height
// else leave the height as it is
//System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
//this.textField.setText(item); // No longer need this!!!
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
}
public class myTextRow {
private final SimpleIntegerProperty ID;
private final SimpleStringProperty text;
private final SimpleStringProperty text2;
public myTextRow(int ID, String text,String text2) {
this.ID = new SimpleIntegerProperty(ID);
this.text = new SimpleStringProperty(text);
this.text2 = new SimpleStringProperty(text2);
}
public void setID(int id) {
this.ID.set(id);
}
public void setText(String text) {
this.text.set(text);
}
public void setText2(String text) {
this.text2.set(text);
}
public int getID() {
return ID.get();
}
public String getText() {
return text.get();
}
public StringProperty textProperty() {
return text;
}
public String getText2() {
return text2.get();
}
public StringProperty text2Property() {
return text2;
}
public IntegerProperty IDProperty() {
return ID;
}
}
private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) {
HBox h = new HBox();
Label l = new Label("Text");
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
double line_height = l.prefHeight(-1);
int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length();
// System.out.println("new lines= "+new_lines);
String[] lines = s.split("\r\n|\r|\n");
// System.out.println("line count func= "+ lines.length);
int count = 0;
//double rest=0;
for (int i = 0; i < lines.length; i++) {
double text_width = get_text_width(lines[i]);
double plus_lines = Math.ceil(text_width / (width - widthCorrector));
if (plus_lines > 1) {
count += plus_lines;
//rest+= (text_width / (width-widthCorrector)) - plus_lines;
} else {
count += 1;
}
}
//count+=(int) Math.ceil(rest);
count += new_lines - lines.length;
return count * line_height + heightCorrector;
}
private static double get_text_width(String s) {
HBox h = new HBox();
Label l = new Label(s);
l.setWrapText(false);
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
// System.out.println("dubbyloop.FXMLDocumentController.get_text_width(): "+l.prefWidth(-1));
return l.prefWidth(-1);
}
}
How can I achieve to read the heights from all Textareas in a row, to compare them and set to the biggest one?
I now add the full code, then it is maybe more clear what I mean.
I have a TableView in JavaFX. It has a field subTotal which depends on the value of the fields quantity and price. I added a new column for the subTotal.
I have textfields present to add a new row to the table. But, the add button wants to have another textfield for the subTotal, although it does not really necessary for the subtotal column.
What I have tried so far :
TableColumn columnCodeProduct = new TableColumn("Product Code");
columnCodeProduct.setMinWidth(100);
columnCodeProduct.setCellValueFactory(new PropertyValueFactory<Data , Integer>("productname "));
TableColumn columnProductName = new TableColumn("Product Name");
columnProductName.setMinWidth(140);
columnProductName.setCellValueFactory(new PropertyValueFactory<Data , String>("codeproduct"));
TableColumn columnPrice = new TableColumn("Price");
columnPrice.setMinWidth(100);
columnPrice.setCellValueFactory(new PropertyValueFactory<Data , Integer>("price"));
TableColumn columQuantity = new TableColumn("Quantity");
columQuantity.setMinWidth(100);
columQuantity.setCellValueFactory(new PropertyValueFactory<Data , Integer>("quantity"));
TableColumn columnTotal = new TableColumn("Sub Total");
columnTotal.setMinWidth(100);
columQuantity.setCellValueFactory(new PropertyValueFactory<Data , Integer>("sub"));
tableData.getColumns().addAll(columnCodeProduct , columnProductName , columnPrice , columQuantity );
tableData.setItems(data);
addButton = new Button("Add Item");
addButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event)
{
if(addproCodeTextfield.getText().isEmpty() || addproNameTextfield.getText().isEmpty()
|| addPriceTextfield.getText().isEmpty() || quantityTextField.getText().isEmpty())
{
System.out.println("Please Add information to all the fields");
} else {
data.add(new Data (
addproCodeTextfield.getText(),
addproNameTextfield.getText(),
addPriceTextfield.getText(),
quantityTextField.getText()));
methodTotal();
}
}
});
Data Class
public class Data
{
private final SimpleStringProperty codeproduct;
private final SimpleStringProperty productname;
private final SimpleStringProperty price ;
private final SimpleStringProperty quantity;
public Data (String code , String proname , String presyo , String quant )
{
this.codeproduct = new SimpleStringProperty(code);
this.productname = new SimpleStringProperty(proname);
this.price = new SimpleStringProperty(presyo);
this.quantity = new SimpleStringProperty(quant);
}
public String getcodeProduct()
{
return codeproduct.get();
}
public String getproductName()
{
return productname.get();
}
public String getPrice()
{
return price.get();
}
public String getQuantity()
{
return quantity.get();
}
}
I would restructure your model class as #ItachiUchiha suggests. If you feel you need to keep the data stored with String representations, you can just create a binding for the subtotal column:
TableColumn<Data, Number> subtotalColumn = new TableColumn<>("Sub Total");
subTotalColumn.setCellValueFactory(cellData -> {
Data data = cellData.getValue();
return Bindings.createDoubleBinding(
() -> {
try {
double price = Double.parseDouble(data.getPrice());
int quantity = Integer.parseInt(data.getQuantity());
return price * quantity ;
} catch (NumberFormatException nfe) {
return 0 ;
}
},
data.priceProperty(),
data.quantityProperty()
);
});
You can take benefit from JavaFX's power to bind value.
Few points to take care of while implementing a scenario as stated above:
The POJO class(in your case Data) fields must have correct types. For example price and quantity must be of SimpleIntegerProperty instead of SimpleStringProperty. This will help us in using Bindings.
SubTotal field depends on the values of price and quantity. The best way to achieve this is to bind subTotalProperty to a multiply Binding of price and quantity.
I have created a (not so) simple example basic editable tableview to show the approach. It has additional features, like editable cells, that you (or others seeking the same problem) might need ;)
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
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.*;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.converter.NumberStringConverter;
public class TableViewSample extends Application {
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);
}
}
}
Screenshot
Note - I have defined setCellFactory and setOnCommit to each of the columns. This is because the name, price and quantity columns are editable. You are most welcome to remove them in case you do not seek editable property.
I want to change the animation which is used between pages change.
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Pagination;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class MainApp1 extends Application
{
final ObservableList<Person> data = FXCollections.observableArrayList(
new Person("1", "Joe", "Pesci"),
new Person("32", "Rhonda", " Fleming's"),
new Person("32", "Humphrey", "Bogart"));
private Pagination pagination;
public static void main(String[] args) throws Exception
{
launch(args);
}
public int itemsPerPage()
{
return 1;
}
public int rowsPerPage()
{
return 5;
}
public VBox createPage(int pageIndex)
{
int lastIndex = 0;
int displace = data.size() % rowsPerPage();
if (displace > 0)
{
lastIndex = data.size() / rowsPerPage();
}
else
{
lastIndex = data.size() / rowsPerPage() - 1;
}
VBox box = new VBox(5);
int page = pageIndex * itemsPerPage();
for (int i = page; i < page + itemsPerPage(); i++)
{
TableView<Person> table = new TableView<>();
TableColumn numCol = new TableColumn("ID");
numCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("num"));
numCol.setMinWidth(20);
TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName"));
firstNameCol.setMinWidth(160);
TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName"));
lastNameCol.setMinWidth(160);
table.getColumns().addAll(numCol, firstNameCol, lastNameCol);
if (lastIndex == pageIndex)
{
table.setItems(FXCollections.observableArrayList(data.subList(pageIndex * rowsPerPage(), pageIndex * rowsPerPage() + displace)));
}
else
{
table.setItems(FXCollections.observableArrayList(data.subList(pageIndex * rowsPerPage(), pageIndex * rowsPerPage() + rowsPerPage())));
}
box.getChildren().add(table);
}
return box;
}
#Override
public void start(final Stage stage) throws Exception
{
pagination = new Pagination((data.size() / rowsPerPage() + 1), 0);
// pagination = new Pagination(20 , 0);
//pagination.setStyle("-fx-border-color:red;");
pagination.setPageFactory(new Callback<Integer, Node>()
{
#Override
public Node call(Integer pageIndex)
{
if (pageIndex > data.size() / rowsPerPage() + 1)
{
return null;
}
else
{
return createPage(pageIndex);
}
}
});
AnchorPane anchor = new AnchorPane();
AnchorPane.setTopAnchor(pagination, 10.0);
AnchorPane.setRightAnchor(pagination, 10.0);
AnchorPane.setBottomAnchor(pagination, 10.0);
AnchorPane.setLeftAnchor(pagination, 10.0);
anchor.getChildren().addAll(pagination);
Scene scene = new Scene(anchor, 400, 250);
stage.setScene(scene);
stage.setTitle("Table pager");
stage.show();
}
public static class Person
{
private final SimpleStringProperty num;
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private Person(String id, String fName, String lName)
{
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
this.num = new SimpleStringProperty(id);
}
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 getNum()
{
return num.get();
}
public void setNum(String id)
{
num.set(id);
}
}
}
Can you tell me how I can do this?
I think that adding animation to the page factory will do the job. I've used the code above and made page slowly appear. See here: http://pastebin.com/5AcCqu95