I'm a novice and would very like a to know how to make a column cell editable when using FXML.
Specifically, I have been following the two working examples provided by Oracle. The first one (http://docs.oracle.com/javafx/2/ui_controls/table-view.htm) allows editing.
The second example ( http://docs.oracle.com/javafx/2/fxml_get_started/fxml_tutorial_intermediate.htm ) suggests at the bottom of the tutorial that it can be edited but doesn't show how this is achieved.
I have read the answers to the related questions but they are beyond my current level ofknowledge.
Can anyone show me how it can be done in as simpler way as possible please?
To save you looking up the tutorial these are the files which I've copied directly from Oracle:
Thanks in advance.
First is FXMLTableView.java
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package fxmltableview;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class FXMLTableView extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("FXML TableView Example");
Pane myPane = (Pane)FXMLLoader.load(getClass().getResource
("fxml_tableview.fxml"));
Scene myScene = new Scene(myPane);
primaryStage.setScene(myScene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The second one is the controller:
package fxmltableview;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
public class FXMLTableViewController {
#FXML private TableView<Person> tableView;
#FXML private TextField firstNameField;
#FXML private TextField lastNameField;
#FXML private TextField emailField;
#FXML
protected void addPerson(ActionEvent event) {
ObservableList<Person> data = tableView.getItems();
data.add(new Person(firstNameField.getText(),
lastNameField.getText(),
emailField.getText()
));
firstNameField.setText("");
lastNameField.setText("");
emailField.setText("");
}
}
The third file is FormattedTableCellFactory.java
package fxmltableview;
import java.text.Format;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.text.TextAlignment;
import javafx.util.Callback;
public class FormattedTableCellFactory<S, T>
implements Callback<TableColumn<S, T>, TableCell<S, T>> {
private TextAlignment alignment;
private Format format;
public TextAlignment getAlignment() {
return alignment;
}
public void setAlignment(TextAlignment alignment) {
this.alignment = alignment;
}
public Format getFormat() {
return format;
}
public void setFormat(Format format) {
this.format = format;
}
#Override
#SuppressWarnings("unchecked")
public TableCell<S, T> call(TableColumn<S, T> p) {
TableCell<S, T> cell = new TableCell<S, T>() {
#Override
public void updateItem(Object item, boolean empty) {
if (item == getItem()) {
return;
}
super.updateItem((T) item, empty);
if (item == null) {
super.setText(null);
super.setGraphic(null);
} else if (format != null) {
super.setText(format.format(item));
} else if (item instanceof Node) {
super.setText(null);
super.setGraphic((Node) item);
} else {
super.setText(item.toString());
super.setGraphic(null);
}
}
};
cell.setTextAlignment(alignment);
switch (alignment) {
case CENTER:
cell.setAlignment(Pos.CENTER);
break;
case RIGHT:
cell.setAlignment(Pos.CENTER_RIGHT);
break;
default:
cell.setAlignment(Pos.CENTER_LEFT);
break;
}
return cell;
}
}
The fourth file is the Person class:
package fxmltableview;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private final SimpleStringProperty firstName = new SimpleStringProperty("");
private final SimpleStringProperty lastName = new SimpleStringProperty("");
private final SimpleStringProperty email = new SimpleStringProperty("");
public Person() {
this("", "", "");
}
public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(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);
}
}
and the last file is the .fxml file:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.cell.*?>
<?import javafx.collections.*?>
<?import fxmltableview.*?>
<GridPane alignment="CENTER" hgap="10.0" vgap="10.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="fxmltableview.FXMLTableViewController">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<children>
<Label style="-fx-font: NORMAL 20 Tahoma;" text="Address Book" GridPane.columnIndex="0" GridPane.rowIndex="0">
</Label>
<TableView fx:id="tableView" editable="true" GridPane.columnIndex="0" GridPane.rowIndex="1">
<columns>
<TableColumn fx:id="firstNameColumn" prefWidth="100" text="First Name">
<cellValueFactory>
<PropertyValueFactory property="firstName" />
</cellValueFactory>
<cellFactory>
<FormattedTableCellFactory alignment="left">
</FormattedTableCellFactory>
</cellFactory>
</TableColumn>
<TableColumn prefWidth="100" text="Last Name">
<cellValueFactory>
<PropertyValueFactory property="lastName" />
</cellValueFactory>
<cellFactory>
<FormattedTableCellFactory alignment="left">
</FormattedTableCellFactory>
</cellFactory>
</TableColumn>
<TableColumn prefWidth="200" text="Email Address">
<cellValueFactory>
<PropertyValueFactory property="email" />
</cellValueFactory>
<cellFactory>
<FormattedTableCellFactory alignment="left">
</FormattedTableCellFactory>
</cellFactory>
</TableColumn>
</columns>
<items>
<FXCollections fx:factory="observableArrayList">
<Person email="jacob.smith#example.com" firstName="Jacob" lastName="Smith" />
<Person email="isabella.johnson#example.com" firstName="Isabella" lastName="Johnson" />
<Person email="ethan.williams#example.com" firstName="Ethan" lastName="Williams" />
<Person email="emma.jones#example.com" firstName="Emma" lastName="Jones" />
<Person email="michael.brown#example.com" firstName="Michael" lastName="Brown" />
</FXCollections>
</items>
<sortOrder>
<fx:reference source="firstNameColumn" />
</sortOrder>
</TableView>
<HBox alignment="bottom_right" spacing="10" GridPane.columnIndex="0" GridPane.rowIndex="2">
<children>
<TextField fx:id="firstNameField" prefWidth="90" promptText="First Name" />
<TextField fx:id="lastNameField" prefWidth="90" promptText="Last Name" />
<TextField fx:id="emailField" prefWidth="150" promptText="email" />
<Button onAction="#addPerson" text="Add" />
</children>
</HBox>
</children>
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
</GridPane>
Related
This question already has answers here:
Javafx tableview not showing data in all columns
(3 answers)
Why should I avoid using PropertyValueFactory in JavaFX?
(1 answer)
Closed last month.
I'm making a product list and products can have multiple parts attached to it, because sometimes a product is made up of multiple parts. This part of the code is to create a new product. I'm trying to copy a selected row from the list of parts to the table of parts that make up the product. The lists are ObservableList types. The logic seems to make sense, but for some reasons the PropertyValueFactory throws out the same error multiple times whenever I click the button to run the copy.
Information:
Java: javafx-sdk-19
OS: Windows 10 Home
IDE: IntelliJ IDEA Community Edition 2022.3
FXML was made with SceneBuilder 19
The four errors :
javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'productID' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory#15ee4827 with provided class type: class InventoryManagementSystem.Outsourced
java.lang.IllegalStateException: Cannot read from unreadable property productID
at javafx.base#19/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:167)
at javafx.controls#19/javafx.scene.control.cell.PropertyValueFactory.getCellDataReflectively(PropertyValueFactory.java:184)
at javafx.controls#19/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:154)
at javafx.controls#19/javafx.scene.control.cell.PropertyValueFactory.call(PropertyValueFactory.java:133)
at javafx.controls#19/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:592)
at javafx.controls#19/javafx.scene.control.TableColumn.getCellObservableValue(TableColumn.java:577)
at javafx.controls#19/javafx.scene.control.TableCell.updateItem(TableCell.java:681)
at javafx.controls#19/javafx.scene.control.TableCell.indexChanged(TableCell.java:485)
at javafx.controls#19/javafx.scene.control.IndexedCell$1.invalidated(IndexedCell.java:85)
at javafx.base#19/javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.base#19/javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:148)
at javafx.controls#19/javafx.scene.control.IndexedCell.updateIndex(IndexedCell.java:130)
at javafx.controls#19/javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:530)
at javafx.controls#19/javafx.scene.control.skin.TableRowSkinBase.<init>(TableRowSkinBase.java:155)
at javafx.controls#19/javafx.scene.control.skin.TableRowSkin.<init>(TableRowSkin.java:82)
at javafx.controls#19/javafx.scene.control.TableRow.createDefaultSkin(TableRow.java:213)
at javafx.controls#19/javafx.scene.control.Control.doProcessCSS(Control.java:886)
at javafx.controls#19/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls#19/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics#19/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:147)
at javafx.graphics#19/javafx.scene.Node.processCSS(Node.java:9603)
at javafx.graphics#19/javafx.scene.Node.applyCss(Node.java:9690)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.setCellIndex(VirtualFlow.java:1811)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.getCell(VirtualFlow.java:1788)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.getOrCreateCellSize(VirtualFlow.java:3026)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.getOrCreateCellSize(VirtualFlow.java:2998)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.recalculateAndImproveEstimatedSize(VirtualFlow.java:3086)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.recalculateEstimatedSize(VirtualFlow.java:3069)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow$5.invalidated(VirtualFlow.java:860)
at javafx.base#19/javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.base#19/javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:148)
at javafx.controls#19/javafx.scene.control.skin.VirtualFlow.setCellCount(VirtualFlow.java:904)
at javafx.controls#19/javafx.scene.control.skin.TableViewSkinBase.updateItemCount(TableViewSkinBase.java:555)
at javafx.controls#19/javafx.scene.control.skin.VirtualContainerBase.checkState(VirtualContainerBase.java:184)
at javafx.controls#19/javafx.scene.control.skin.VirtualContainerBase.layoutChildren(VirtualContainerBase.java:159)
at javafx.controls#19/javafx.scene.control.skin.TableViewSkinBase.layoutChildren(TableViewSkinBase.java:407)
at javafx.controls#19/javafx.scene.control.Control.layoutChildren(Control.java:588)
at javafx.graphics#19/javafx.scene.Parent.layout(Parent.java:1207)
at javafx.graphics#19/javafx.scene.Parent.layout(Parent.java:1214)
at javafx.graphics#19/javafx.scene.Parent.layout(Parent.java:1214)
at javafx.graphics#19/javafx.scene.Scene.doLayoutPass(Scene.java:592)
at javafx.graphics#19/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2512)
at javafx.graphics#19/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:407)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
at javafx.graphics#19/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:406)
at javafx.graphics#19/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:436)
at javafx.graphics#19/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:575)
at javafx.graphics#19/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:555)
at javafx.graphics#19/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:548)
at javafx.graphics#19/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:352)
at javafx.graphics#19/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics#19/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics#19/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:184)
at java.base/java.lang.Thread.run(Thread.java:1589)
javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'productName' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory#4f5b087e with provided class type: class
[THE REST OF THE ERROR IS THE SAME AS THE FIRST ERROR]
javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'productInventory' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory#276f30b0 with provided class type: class
[THE REST OF THE ERROR IS THE SAME AS THE FIRST ERROR]
javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'productPrice' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory#6b95e213 with provided class type: class
[THE REST OF THE ERROR IS THE SAME AS THE FIRST ERROR]
Code:
Note - I stubbed out unrelated methods for readability.
Controller Code: By my best deduction, the errors are thrown in the addProductAddButton after linkedPartsTable.setItems(linkedParts); runs.
package Controllers;
import InventoryManagementSystem.Inventory;
import InventoryManagementSystem.Part;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.Optional;
import java.util.ResourceBundle;
public class AddProductFormController implements Initializable {
#FXML private TextField partsSearchField;
#FXML private TextField productIDField;
#FXML private TextField productNameField;
#FXML private TextField productInventoryField;
#FXML private TextField productPriceField;
#FXML private TextField productMaxField;
#FXML private TextField productMinField;
#FXML private TableView<Part> availablePartsTable;
#FXML private TableColumn<?, ?> partsIDColumn;
#FXML private TableColumn<?, ?> partsNameColumn;
#FXML private TableColumn<?, ?> partsInventoryColumn;
#FXML private TableColumn<?, ?> partsPriceColumn;
#FXML private TableView<Part> linkedPartsTable;
#FXML private TableColumn<?, ?> linkedPartsIDColumn;
#FXML private TableColumn<?, ?> linkedPartsNameColumn;
#FXML private TableColumn<?, ?> linkedPartsInventoryColumn;
#FXML private TableColumn<?, ?> linkedPartsPriceColumn;
#FXML private Button addButton;
#FXML private Button removeButton;
#FXML private Button cancelButton;
#FXML private Button saveButton;
private ObservableList<Part> linkedParts = FXCollections.observableArrayList();
Stage stage;
Parent scene;
#Override
public void initialize(URL url, ResourceBundle rb)
{
partsIDColumn.setCellValueFactory(new PropertyValueFactory<>("partID"));
partsNameColumn.setCellValueFactory(new PropertyValueFactory<>("partName"));
partsInventoryColumn.setCellValueFactory(new PropertyValueFactory<>("partInventory"));
partsPriceColumn.setCellValueFactory(new PropertyValueFactory<>("partPrice"));
availablePartsTable.setItems(Inventory.allParts);
linkedPartsIDColumn.setCellValueFactory(new PropertyValueFactory<>("productID"));
linkedPartsNameColumn.setCellValueFactory(new PropertyValueFactory<>("productName"));
linkedPartsInventoryColumn.setCellValueFactory(new PropertyValueFactory<>("productInventory"));
linkedPartsPriceColumn.setCellValueFactory(new PropertyValueFactory<>("productPrice"));
linkedPartsTable.setItems(linkedParts);
productIDField.setText("Automatically Generated");
productIDField.setDisable(true);
}
#FXML private void Search() {}
#FXML private void addProductAddButton(ActionEvent event) throws IOException
{
Part selectedPart = availablePartsTable.getSelectionModel().getSelectedItem();
if(selectedPart != null)
{
linkedParts.add(selectedPart);
linkedPartsTable.setItems(linkedParts);
}
else
{
System.out.println("here 6");
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Error!");
alert.setHeaderText(null);
alert.setContentText("No Part Selected.");
alert.showAndWait();
}
}
#FXML private void addProductRemoveButton(ActionEvent event) throws IOException {}
#FXML private void addProductSaveButton(ActionEvent event) throws IOException {}
#FXML private void addProductCancelButton(ActionEvent event) throws IOException {}
}
Imported Part Code:
package InventoryManagementSystem;
public class Part
{
private int partID, partInventory, partMin, partMax;
private String partName, partAdaptive;
private Double partPrice;
public Part(int partID, String partName, double partPrice, int partInventory, int partMin, int partMax, String partAdaptive)
{
this.partID = partID;
this.partName = partName;
this.partPrice = partPrice;
this.partInventory = partInventory;
this.partMin = partMin;
this.partMax = partMax;
this.partAdaptive = partAdaptive;
}
public int getPartID() { return partID; }
public String getPartName() { return partName; }
public double getPartPrice() { return partPrice; }
public int getPartInventory() { return partInventory; }
public int getPartMin() { return partMin; }
public int getPartMax() { return partMax; }
public String getPartAdaptive() { return partAdaptive; }
public void setPartID(int partID) { this.partID = partID; }
public void setPartName(String partName) { this.partName = partName; }
public void setPartPrice(double partPrice) { this.partPrice = partPrice; }
public void setPartInventory(int partInventory) { this.partInventory = partInventory; }
public void setPartMin(int partMin) { this.partMin = partMin; }
public void setPartMax(int partMax) { this.partMax = partMax; }
public void setAdaptive(String partAdaptive) { this.partAdaptive = partAdaptive; }
}
Imported Inventory Code:
package InventoryManagementSystem;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Inventory
{
public static ObservableList<Part> allParts = FXCollections.observableArrayList();
public static ObservableList<Product> allProducts = FXCollections.observableArrayList();
private static int inventoryPartID;
private static int inventoryProductID;
public static ObservableList<Part> getAllParts() { return allParts; }
public static int inventoryPartID()
{
inventoryPartID++;
return inventoryPartID;
}
public static Part lookupPart(int partID)
{
for(Part p : allParts)
{
if (p.getPartID() == partID)
{
return p;
}
}
return null;
}
public static void addPart(Part newPart) { allParts.add(newPart); }
public static void updatePart(Part selectedPart) { allParts.set(selectedPart.getPartID() - 1, selectedPart); }
public static boolean deletePart(int selectedPart)
{
for(Part p : allParts)
{
if (p.getPartID() == selectedPart)
{
allParts.remove(p);
return true;
}
}
return false;
}
public static ObservableList<Product> getAllProducts() { return allProducts; }
public static int inventoryProductID()
{
inventoryProductID++;
return inventoryProductID;
}
public static Product lookupProduct(int productID)
{
for(Product p : allProducts)
{
if (p.getProductID() == productID)
{
return p;
}
}
return null;
}
public static void addProduct(Product newProduct) { allProducts.add(newProduct); }
public static void updatedProduct(Product newProduct) { allProducts.set(newProduct.getProductID(), newProduct); }
public static boolean deleteProduct(int selectedProduct)
{
for(Product p : allProducts)
{
if (p.getProductID() == selectedProduct)
{
allProducts.remove(p);
return true;
}
}
return false;
}
}
Outsourced Code referenced in the error:
package InventoryManagementSystem;
public class Outsourced extends Part
{
private String companyName;
public Outsourced(int id, String name, double price, int inventory, int min, int max, String adaptive)
{
super(id, name, price, inventory, min, max, adaptive);
this.companyName = companyName;
}
public String getCompanyName() { return companyName; }
public void setCompanyName(String companyName) { this.companyName = companyName; }
}
FXML file in case it helps:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>
<AnchorPane prefHeight="400.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controllers.AddProductFormController">
<children>
<Pane prefHeight="800.0" prefWidth="1000.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<Label text="Add Product" AnchorPane.leftAnchor="20.0" AnchorPane.topAnchor="20.0">
<font>
<Font name="System Bold" size="20.0" />
</font>
</Label>
<TextField fx:id="partsSearchField" onAction="#onEnter" prefHeight="25.0" prefWidth="159.0" promptText="Search by Part ID or Name" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0" />
<AnchorPane prefHeight="275.0" prefWidth="450.0" AnchorPane.leftAnchor="20.0" AnchorPane.topAnchor="100.0">
<children>
<GridPane prefHeight="275.0" prefWidth="450.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="122.0" minWidth="10.0" prefWidth="108.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="162.0" minWidth="10.0" prefWidth="154.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="124.0" minWidth="8.0" prefWidth="75.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="165.0" minWidth="10.0" prefWidth="94.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="ID" />
<Label text="Name" GridPane.rowIndex="1" />
<Label text="Inventory" GridPane.rowIndex="2" />
<Label text="Price/Cost" GridPane.rowIndex="3" />
<Label text="Max" GridPane.rowIndex="4" />
<TextField fx:id="productIDField" promptText="Product ID" GridPane.columnIndex="1" />
<TextField fx:id="productNameField" promptText="Product Name" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<TextField fx:id="productInventoryField" promptText="Available Units" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="productPriceField" promptText="Price/Cost" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<TextField fx:id="productMaxField" promptText="Max Units" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Label alignment="CENTER" text="Min" GridPane.columnIndex="2" GridPane.rowIndex="4">
<padding>
<Insets left="35.0" />
</padding>
</Label>
<TextField fx:id="productMinField" promptText="Min Units" GridPane.columnIndex="3" GridPane.rowIndex="4" />
</children>
</GridPane>
</children>
</AnchorPane>
<AnchorPane prefHeight="275.0" prefWidth="450.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="60.0">
<children>
<Rectangle arcHeight="5.0" arcWidth="5.0" fill="TRANSPARENT" height="275.0" stroke="BLACK" strokeLineCap="ROUND" strokeType="INSIDE" width="450.0" />
<TableView fx:id="availablePartsTable" layoutY="-1.0" prefHeight="275.0" prefWidth="448.0" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="1.0">
<columns>
<TableColumn fx:id="partsIDColumn" prefWidth="75.0" text="Part ID" />
<TableColumn fx:id="partsNameColumn" prefWidth="153.0" text="Part Name" />
<TableColumn fx:id="partsInventoryColumn" prefWidth="100.0" text="Inventory Level" />
<TableColumn fx:id="partsPriceColumn" prefWidth="120.0" text="Price/Cost Per Unit" />
</columns>
</TableView>
</children>
</AnchorPane>
<Button fx:id="addButton" mnemonicParsing="false" onAction="#addProductAddButton" text="Add" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="350.0" />
<AnchorPane prefHeight="275.0" prefWidth="450.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="400.0">
<children>
<Rectangle arcHeight="5.0" arcWidth="5.0" fill="TRANSPARENT" height="275.0" stroke="BLACK" strokeLineCap="ROUND" strokeType="INSIDE" width="450.0" />
<TableView fx:id="linkedPartsTable" layoutY="-1.0" prefHeight="275.0" prefWidth="448.0" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="1.0">
<columns>
<TableColumn fx:id="linkedPartsIDColumn" prefWidth="75.0" text="Part ID" />
<TableColumn fx:id="linkedPartsNameColumn" prefWidth="153.0" text="Part Name" />
<TableColumn fx:id="linkedPartsInventoryColumn" prefWidth="100.0" text="Inventory Level" />
<TableColumn fx:id="linkedPartsPriceColumn" prefWidth="120.0" text="Price/Cost Per Unit" />
</columns>
</TableView>
</children>
</AnchorPane>
<Button fx:id="removeButton" mnemonicParsing="false" onAction="#addProductRemoveButton" text="Remove Associated Part" AnchorPane.bottomAnchor="55.0" AnchorPane.rightAnchor="20.0" />
<Button fx:id="saveButton" mnemonicParsing="false" onAction="#addProductSaveButton" text="Save" AnchorPane.bottomAnchor="20.0" AnchorPane.rightAnchor="80.0" />
<Button fx:id="cancelButton" mnemonicParsing="false" onAction="#addProductCancelButton" text="Cancel" AnchorPane.bottomAnchor="20.0" AnchorPane.rightAnchor="20.0" />
</children>
</AnchorPane>
So I've tried to follow this as closely as I could but when I run my program it just displays an empty listview, instead of my custom listcells; and without showing any error.
Big light grey rectangle in the middle is the listview.
Here is my code:-
Main FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="1045.0" prefWidth="1770.0" style="-fx-background-color: #2E2E2E;" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.BuyerVendors">
<children>
<AnchorPane layoutX="70.0" layoutY="40.0" prefHeight="900.0" prefWidth="1630.0" style="-fx-background-color: #404040;">
<opaqueInsets>
<Insets />
</opaqueInsets>
<children>
<ListView fx:id="listview" layoutX="125.0" layoutY="92.0" prefHeight="900.0" prefWidth="1630.0" style="-fx-background-color: #404040;" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</children>
</AnchorPane>
Listcell FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.Cursor?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.text.Font?>
<fx:root maxHeight="200.0" maxWidth="1630.0" minHeight="200.0" minWidth="1630.0" prefHeight="200.0" prefWidth="1630.0" style="-fx-background-color: #404040;" type="AnchorPane" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label fx:id="name" layoutX="200.0" layoutY="35.0" maxHeight="600.0" prefWidth="600.0" text="Abc Xyz Fresh Greens" textFill="WHITE" underline="true">
<font>
<Font size="30.0" />
</font>
</Label>
<Label fx:id="address" alignment="TOP_LEFT" layoutX="200.0" layoutY="100.0" maxHeight="63.0" maxWidth="600.0" prefHeight="63.0" prefWidth="600.0" text="East of Trodden, 910 019." textFill="WHITE" wrapText="true">
<font>
<Font size="18.0" />
</font>
</Label>
<ImageView fitHeight="36.0" fitWidth="36.0" layoutX="1000.0" layoutY="35.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="#../../icons/star.png" />
</image>
</ImageView>
<Label fx:id="stars" layoutX="1050.0" layoutY="45.0" text="4.9/5" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
</Label>
<Label fx:id="reviews" layoutX="1100.0" layoutY="45.0" text="(200 reviews)" textFill="WHITE">
<font>
<Font size="18.0" />
</font>
</Label>
<Label fx:id="email" layoutX="1000.0" layoutY="103.0" text="Contact: abc.xyz#gmail.com" textFill="WHITE" />
</children>
<cursor>
<Cursor fx:constant="HAND" />
</cursor>
</fx:root>
Main controller class along with object 'Vendors' and listcell controller class:
package application;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
//Controller class for Vendors listview
public class BuyerVendors implements Initializable {
//Getters, setters and constructor for list/listview object
public static class Vendors {
String email, name, address, no_of_reviews, rating;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getRating() {
return rating;
}
public void setRating(String rating) {
this.rating = rating;
}
public String getNo_of_reviews() {
return no_of_reviews;
}
public void setNo_of_reviews(String no_of_reviews) {
this.no_of_reviews = no_of_reviews;
}
public Vendors(String email, String name, String address, String rating, String no_of_reviews) {
super();
this.email = email;
this.name = name;
this.address = address;
this.rating = rating;
this.no_of_reviews = no_of_reviews;
}
}
ObservableList<Vendors> list;
//Controller class for Vendors listcell
public class VendorsCell extends ListCell<Vendors> {
#FXML
private Label name;
#FXML
private Label address;
#FXML
private Label stars;
#FXML
private Label reviews;
#FXML
private Label email;
public VendorsCell() {
loadFXML();
}
private void loadFXML() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("../FXML files/VendorsCell.fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void updateItem(Vendors item, boolean empty) {
super.updateItem(item, empty);
if(empty) {
setText(null);
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
else {
name.setText(item.getName());
address.setText(item.getAddress());
if(item.getRating() == null) {
stars.setText("No ratings yet");
reviews.setText("");
}
else {
stars.setText(item.getRating());
reviews.setText(item.getNo_of_reviews());
}
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
}
//CellFactory
public class VendorsCellFactory implements Callback<ListView<Vendors>, ListCell<Vendors>> {
#Override
public ListCell<Vendors> call(ListView<Vendors> param) {
return new VendorsCell();
}
}
#FXML
private ListView<Vendors> listview;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
try {
list = UserDB.displayVendors(); // Function that returns observable list from database
} catch (SQLException e) {
e.printStackTrace();
}
listview = new ListView<Vendors>(list);
listview.setCellFactory(new VendorsCellFactory());
}
}
PS: Please excuse me if there are some silly errors; I don't have much experience using javaFX or java itself. :(
This is what my view looks like:
Explanation
The entire window itself runs on one controller, called the CartWindowController, and the product list itself is a JavaFX Custom Control called CartItemComponent, which has it's own controller. Each item in the list, therefore has it's own instance of the controller as I programmatically make an instance and populate a VBox.
Problem
I cannot figure out how to notify the CartWindowController when the user clicks on the "X" button, which is handled by the "CartItemComponent" Controller. I would highly appreciate it if anyone could give me a heads up on how to tackle this problem.
Here's what my FXML looks like for the entire Window:
CartWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorPane" fx:id="parent" prefHeight="400.0" prefWidth="600.0" styleClass="pane" stylesheets="#../assets/userwindow.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ordermanagementsystem.controllers.CartWindowController">
<children>
<Button layoutX="25.0" layoutY="25.0" mnemonicParsing="false" onAction="#exitWindow" prefHeight="35.0" prefWidth="20.0" styleClass="back-button" />
<Label layoutX="262.0" layoutY="17.0" styleClass="heading" text="Cart" />
<ScrollPane hbarPolicy="NEVER" layoutY="97.0" prefHeight="315.0" prefWidth="600.0" styleClass="no-padding">
<content>
<AnchorPane prefWidth="600.0" styleClass="no-padding">
<children>
<VBox fx:id="productList" layoutX="25.0" prefWidth="350.0" />
<AnchorPane layoutX="425.0" layoutY="25.0" prefWidth="150.0" styleClass="no-padding">
<children>
<Label layoutX="18.0" styleClass="heading-sub" text="Summary" />
<Label layoutX="1.0" layoutY="55.0" text="Gross:" />
<Label fx:id="grossTotal" alignment="CENTER_RIGHT" layoutX="47.0" layoutY="55.0" prefHeight="17.0" prefWidth="103.0" text="RM0.00" />
<Label layoutX="1.0" layoutY="75.0" text="Packaging:" />
<Label fx:id="packagingTotal" alignment="CENTER_RIGHT" layoutX="73.0" layoutY="75.0" prefHeight="17.0" prefWidth="77.0" text="RM0.00" />
<Label layoutX="1.0" layoutY="95.0" text="Total:" />
<Label fx:id="total" alignment="CENTER_RIGHT" layoutX="40.0" layoutY="95.0" prefHeight="17.0" prefWidth="110.0" styleClass="green-text" text="RM0.00" />
<Button layoutY="125.0" mnemonicParsing="false" onAction="#checkout" prefHeight="39.0" prefWidth="150.0" styleClass="action-button" text="Check Out" />
</children>
</AnchorPane>
</children>
</AnchorPane>
</content>
</ScrollPane>
</children>
</AnchorPane>
CartWindowController.java
package ordermanagementsystem.controllers;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import ordermanagementsystem.cart.CartState;
import ordermanagementsystem.orders.models.OrderItem;
import ordermanagementsystem.viewcomponents.CartItemComponent;
public class CartWindowController extends ViewController implements Initializable {
#FXML
public Parent parent;
#FXML
private VBox productList;
#FXML
private Label grossTotal;
#FXML
private Label packagingTotal;
#FXML
private Label total;
private CartState cartState;
#FXML
private void exitWindow(ActionEvent event) {
try {
this.openPage(this.parent, "MainWindow.fxml");
} catch (IOException ex) {
ex.printStackTrace();
}
}
#FXML
private void checkout(ActionEvent event) {
}
#Override
public void initialize(URL url, ResourceBundle rb) {
this.cartState = CartState.getInstance();
for (OrderItem item : this.cartState.getItems()) {
this.productList.getChildren().add(new CartItemComponent(item));
}
}
}
CartItemComponent.java:
package ordermanagementsystem.viewcomponents;
import java.io.IOException;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import ordermanagementsystem.DialogBox;
import ordermanagementsystem.cart.CartState;
import ordermanagementsystem.orders.models.OrderItem;
public class CartItemComponent extends AnchorPane {
#FXML
private AnchorPane frame;
#FXML
private TextField quantity;
#FXML
private Label total;
#FXML
private Label productName;
private OrderItem item;
private CartState cartState;
public CartItemComponent(OrderItem item) {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/ordermanagementsystem/views/components/CartItemComponent.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
exception.getStackTrace();
}
this.cartState = CartState.getInstance();
this.item = item;
this.setQuantity(1);
this.quantity.setEditable(false);
this.productName.setText(this.item.getProduct().getName());
}
private void setQuantity(int quantity) {
this.quantity.setText(String.valueOf(quantity));
this.item.setQuantity(quantity);
this.cartState.updateItem(this.item);
this.total.setText("RM" + String.format("%.2f", item.getProduct().getPrice() * quantity));
}
private int getQuantity() {
return Integer.parseInt(this.quantity.getText());
}
private void updateSummary() {
}
#FXML
private void add(ActionEvent event) {
int quantity = this.getQuantity();
if (quantity == 99) {
DialogBox.showValidationDialog("The quantity cannot be over 99.");
} else {
this.setQuantity(quantity + 1);
}
}
#FXML
private void substract(ActionEvent event) {
int quantity = this.getQuantity();
if (quantity == 1) {
DialogBox.showValidationDialog("The quantity cannot be below 1.");
} else {
this.setQuantity(quantity - 1);
}
}
}
Something you could try is to pass the CartWindowController into the CartItemComponent constructor, then when you need to notify the CartWindowController, you call a method or set a flag or trigger an event, your choice! All you would need to do is add a parameter of type CartWindowController to you CartItemComponent and just save the reference.
Goal:
Display data, below, inside of the table
"Jacob", "Smith", "jacob.smith#example.com"
"Isabella", "Johnson", "isabella.johnson#example.com"
"Ethan", "Williams", "ethan.williams#example.com"
"Emma", "Jones", "emma.jones#example.com"
"Michael", "Brown", "michael.brown#example.com"
Problem:
What code am I missing in order to display the data inside of the table?
Info:
I'm new in JavaFX.
I'm using netbeans
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="787.0" prefWidth="1086.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TableView id="ttt" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn id="firstNameCol" prefWidth="124.0" text="First name" />
<TableColumn id="lastNameCol" prefWidth="139.0" text="Last name" />
<TableColumn id="emailCol" minWidth="7.0" prefWidth="197.0" text="Email" />
<TableColumn id="addressCol" prefWidth="105.0" text="Address" />
<TableColumn id="zipcodeCol" prefWidth="100.0" text="Zipcode" />
<TableColumn id="cityCol" prefWidth="204.0" text="City" />
</columns>
</TableView>
</center>
</BorderPane>
package dreamcrm;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class DreamCRM extends Application {
private TableView<Person> table = new TableView<Person>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#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")
);
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
package dreamcrm;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
public class FXMLDocumentController implements Initializable {
#FXML
private Label label;
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
}
package dreamcrm;
import javafx.beans.property.SimpleStringProperty;
public class Person {
private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;
private final SimpleStringProperty email;
public 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 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);
}
}
You will want to use fx:id instead of id for this. fx:id will still work with CSS selectors, so no worries there.
As #fabian pointed out, and that I missed, you also need to add the fx:controller in your fxml file so that it knows what is going to control it.
In your document controller, you will need to let it know it is getting some info from your fxml document using #FXML
So like this,
#FXML
private TableView ttt;
#FXML
private TableColumn<Person, String> firstNameCol, lastNameCol, emailCol,addressCol, zipCol, cityCol;
Here, you use your fx:id as the variable name.
Then, in your initialize function, you will need to set the cellValueFactory, like so.
#FXML
public void initialize(){
firstNamecol.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
//etc..
//Don't forget to add your list that you made to the tableview
ttt.setItems(list);
}
After you add the ObservableList you can now add and remove items and it should update accordingly.
On a related note, you need to have SimpleStringProperty as a returnable value, i.e.
public StringProperty firstNameProperty(){
return firstName;
}
This should get you started.
I am unable to populate my tableview. I believe the problem is in the controller, in the way my data is being sent to the FXML file, because a system out print (see below) shows exactly what I have in my database.
Please let me know where I did a mistake. I went over all tutorials that exist on that, but nothing fits my problem.
Thanks
Main App:
package tableview;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class MainApp extends Application {
public static void main(String[] args) {
// TODO Auto-generated method stub
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("view/FXMLTable.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Controller:
import tableview.model.Person;
public class FXMLTableController{
#FXML
public TableView<Person> tableview ;
#FXML
private TableColumn<Person, Number> clientIdColumn;
#FXML
private TableColumn<Person, String> firstNameColumn;
#FXML
private TableColumn<Person, String> lastNameColumn;
#FXML
private void initialize() {
assert tableview != null : "fx:id=\"tableview\" was not injected: check your FXML file 'UserMaster.fxml'.";
clientIdColumn.setCellValueFactory(cellData -> cellData.getValue().
clientIDProperty());
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue()
.firstNameProperty());
lastNameColumn.setCellValueFactory(cellData -> cellData.getValue()
.lastNameProperty());
buildData();
}
private ObservableList<Person> data;
public void buildData(){
data = FXCollections.observableArrayList();
Connection con = null;
try {
Class.forName("org.sqlite.JDBC");
con = DriverManager.getConnection("jdbc:sqlite:tableviewdb.db");
String SQL = "Select * from INFO";
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Person per = new Person();
per.ClientID.set(rs.getInt("CLIENTID"));
per.FirstName.set(rs.getString("FIRSTNAME"));
per.LastName.set(rs.getString("LASTNAME"));
data.add(per);
}
tableview = new TableView<Person>();
tableview.setItems(data);
System.out.println(tableview.getItems().get(1).ClientID);
}
catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
}
Model Class:
package tableview.model;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
public SimpleIntegerProperty ClientID = new SimpleIntegerProperty();
public SimpleStringProperty FirstName = new SimpleStringProperty();
public SimpleStringProperty LastName = new SimpleStringProperty();
public SimpleIntegerProperty getClientID() {
return ClientID;
}
public SimpleStringProperty getFirstname() {
return FirstName;
}
public SimpleStringProperty getLastName() {
return LastName;
}
public IntegerProperty clientIDProperty(){
return ClientID;
}
public StringProperty firstNameProperty(){
return FirstName;
}
public StringProperty lastNameProperty(){
return LastName;
}
}
FXML file:
(disregard the save button for now...)
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<SplitPane prefHeight="400.0" prefWidth="600.0">
<items>
<SplitPane dividerPositions="0.5" orientation="VERTICAL" prefHeight="200.0" prefWidth="160.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<TextField layoutX="93.0" layoutY="34.0" />
<TextField layoutX="93.0" layoutY="85.0" />
<Label layoutX="35.0" layoutY="39.0" text="name" />
<Label layoutX="35.0" layoutY="90.0" text="email" />
<Button layoutX="204.0" layoutY="140.0" mnemonicParsing="false" text="save" />
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0">
<children>
<TableView layoutY="-2.0" prefHeight="200.0" prefWidth="598.0">
<columns>
<TableColumn prefWidth="302.0" text="name" />
<TableColumn prefWidth="295.0" text="email" />
</columns>
</TableView>
</children>
</AnchorPane>
</items>
</SplitPane>
</items>
</SplitPane>
</children>
</AnchorPane>
You're creating a new TableView and setting its items, instead of setting the items on the table that the FXML file defined. Remove the
tableView = new TableView<Person>();
from the controller.
To get the #FXML-annotated fields in the controller to be populated with the appropriate elements from the FXML file, you need to add fx:id attributes to those elements:
<TableView fx:id="tableview" ... >
<columns>
<TableColumn fx:id="firstNameColumn" ... />
...