I have a particular TreeTableView that displays a hierarchical tree of mixed types. These types do not necessarily have overlapping columns and as such the columns for some rows will be empty. As an example, consider the following classes:
public class Person {
private final StringProperty nameProperty;
private final StringProperty surnameProperty;
public Person() {
this.nameProperty = new SimpleStringProperty();
this.surnameProperty = new SimpleStringProperty();
}
public StringProperty nameProperty() {
return this.nameProperty;
}
public void setName(String value) {
this.nameProperty.set(value);
}
public String getName() {
return this.nameProperty.get();
}
public StringProperty surnameProperty() {
return this.surnameProperty;
}
public void setSurname(String value) {
this.surnameProperty.set(value);
}
public String getSurname() {
return this.surnameProperty.get();
}
}
public class Dog {
private final StringProperty nameProperty;
private final IntegerProperty ageProperty;
private final StringProperty breedProperty;
public Dog() {
this.nameProperty = new SimpleStringProperty();
this.ageProperty = new SimpleIntegerProperty();
this.breedProperty = new SimpleStringProperty();
}
public StringProperty nameProperty() {
return this.nameProperty;
}
public void setName(String value) {
this.nameProperty.set(value);
}
public String getName() {
return this.nameProperty.get();
}
public IntegerProperty ageProperty() {
return this.ageProperty;
}
public void setAge(int value) {
this.ageProperty.setValue(value);
}
public int getAge() {
return this.ageProperty.get();
}
public StringProperty breedProperty() {
return this.breedProperty;
}
public void setBreed(String breed) {
this.breedProperty.set(breed);
}
public String getBreed() {
return this.breedProperty.get();
}
}
If I construct the TreeTableView as follows:
TreeTableView<Object> treeTableView = new TreeTableView<>();
treeTableView.setEditable(true);
List<TreeTableColumn<Object, ?>> columns = treeTableView.getColumns();
TreeTableColumn<Object, String> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("name"));
nameColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
columns.add(nameColumn);
TreeTableColumn<Object, String> surnameColumn = new TreeTableColumn<>("Surname");
surnameColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
surnameColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("surname"));
columns.add(surnameColumn);
TreeTableColumn<Object, Integer> ageColumn = new TreeTableColumn<>("Age");
ageColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn(new IntegerStringConverter()));
ageColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("age"));
columns.add(ageColumn);
TreeTableColumn<Object, String> breedColumn = new TreeTableColumn<>("Breed");
breedColumn.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
breedColumn.setCellValueFactory(new TreeItemPropertyValueFactory<>("breed"));
columns.add(breedColumn);
TreeItem<Object> rootItem = new TreeItem<>();
treeTableView.setRoot(rootItem);
treeTableView.setShowRoot(false);
List<TreeItem<Object>> rootChildren = rootItem.getChildren();
Person john = new Person();
john.setName("John");
john.setSurname("Denver");
TreeItem<Object> johnTreeItem = new TreeItem<>(john);
rootChildren.add(johnTreeItem);
List<TreeItem<Object>> johnChildren = johnTreeItem.getChildren();
Dog charlie = new Dog();
charlie.setName("Charlie");
charlie.setAge(4);
charlie.setBreed("Labrador");
TreeItem<Object> charlieTreeItem = new TreeItem<>(charlie);
johnChildren.add(charlieTreeItem);
Dog daisy = new Dog();
daisy.setName("Daisy");
daisy.setAge(7);
daisy.setBreed("Bulldog");
TreeItem<Object> daisyTreeItem = new TreeItem<>(daisy);
johnChildren.add(daisyTreeItem);
I will get a TreeTableView that looks like:
The Age and Breed columns are empty for the TreeItems that contains Person objects. However, nothing stops me from editing Age or Breed cell for the top-most Person row. Setting a value in one of those cells doesn't change the Person object, but the value still hangs around there like it is committed.
Is there any way to prevent this from happening? I know that I could check for nulls in a custom TreeTableCell subclass and prevent the editing from kicking off in the startEdit() method. However, there are circumstances where a null-value is valid and preventing editing by checking nulls is not a feasible solution for all situations. Also, creating a custom TreeTableCell subclass for every datatype and corresponding columns is painful. It would have been nice if TreeItemPropertyValueFactory could provide for a way to abort the edit when no value is present for a particular cell.
Ok, I scraped together something by looking at the TreeItemPropertyValueFactory class itself for inspiration. This gives me the desired functionality, although I'm not sure if it is 100% correct or what the implications are of using it.
It basically comes down to installing a new cell-factory that checks if the cell-value-factory is of type TreeItemPropertyValueFactory. If it is the case, a new cell-factory is installed that delegates to the original but adds listeners for the table-row and tree-item properties. When the TreeItem changes, we get the row-data and see if we can access the desired property (via a PropertyReference that is cached for performance). If we can't (and we get the two exceptions) we assume that the property cannot be accessed and we set the cell's editable-property to false.
public <S, T> void disableUnavailableCells(TreeTableColumn<S, T> treeTableColumn) {
Callback<TreeTableColumn<S, T>, TreeTableCell<S, T>> cellFactory = treeTableColumn.getCellFactory();
Callback<CellDataFeatures<S, T>, ObservableValue<T>> cellValueFactory = treeTableColumn.getCellValueFactory();
if (cellValueFactory instanceof TreeItemPropertyValueFactory) {
TreeItemPropertyValueFactory<S, T> valueFactory = (TreeItemPropertyValueFactory<S, T>)cellValueFactory;
String property = valueFactory.getProperty();
Map<Class<?>, PropertyReference<T>> propertyRefCache = new HashMap<>();
treeTableColumn.setCellFactory(column -> {
TreeTableCell<S, T> cell = cellFactory.call(column);
cell.tableRowProperty().addListener((o1, oldRow, newRow) -> {
if (newRow != null) {
newRow.treeItemProperty().addListener((o2, oldTreeItem, newTreeItem) -> {
if (newTreeItem != null) {
S rowData = newTreeItem.getValue();
if (rowData != null) {
Class<?> rowType = rowData.getClass();
PropertyReference<T> reference = propertyRefCache.get(rowType);
if (reference == null) {
reference = new PropertyReference<>(rowType, property);
propertyRefCache.put(rowType, reference);
}
try {
reference.getProperty(rowData);
} catch (IllegalStateException e1) {
try {
reference.get(rowData);
} catch (IllegalStateException e2) {
cell.setEditable(false);
}
}
}
}
});
}
});
return cell;
});
}
}
For the example listed in the question, you can call it after you created all your columns as:
...
columns.forEach(this::disableUnavailableCells);
TreeItem<Object> rootItem = new TreeItem<>();
treeTableView.setRoot(rootItem);
treeTableView.setShowRoot(false);
...
You'll see that cells for the Age and Breed columns are now uneditable for Person entries whereas cells for the Surname column is now uneditable for Dog entries, which is what we want. Cells for the common Name column is editable for all entries as this is a common property among Person and Dog objects.
Related
I have several classes that all inherit from one super class that need to populate several TableViews related to their class.
The super class is abstract and some of the getters and setters are final but still contains data needed to populate the cells.
Writing a new Callback class for each and every column is doable, but I'm looking for a way to implements this.
sample code
class SuperClass
{
protected String name;
protected double value;
public final void setName(String name)
{
this.name = name;
}
public final void getName()
{
return this.name;
}
public final void setValue(double value)
{
this.value = value;
}
public double getValue()
{
return this.value;
}
}
class SubClass1 extends SuperClass
{
private int id;
public void setId(int id)
{
this.id = id;
}
public int getId()
{
return this.id;
}
}
class SubClass2 extends SuperClass
{
private String location;
public void setLocation(String location)
{
this.location = location;
}
}
class SubClass3 extends SuperClass
{
private ObservableMap<SuperClass> map;
public ObservableMap<SuperClass> map()
{
return this.map;
}
}
TableView
TableColumn<SubClass1, Integer> tc1_id;
TableColumn<SubClass1, String> tc1_name;
TableColumn<SubClass1, Double> tc1_value;
TableColumn<SubClass2, String> tc2_loc;
TableColumn<SubClass2, String> tc2_name;
TableColumn<SubClass2, Double> tc2_value;
TableColumn<SubClass3, String> tc3_name;
TableColumn<SubClass3, Double> tc3_value;
Here's a reference of what I was going to do...
Accessing Subclass properties in a JavaFX TableView ObservableArrayList
But just with the sample code, I'm basically rewriting 2 methods, 3 times each... and there's a bit more than that in the actual program. (Just a smidge more)
I think you are just asking how to reduce the amount of code you have to write. The solution is just the same as any such question: write a method that performs the repetitive part, and parametrize it with the parts that vary. So in this case, you just need to write a generic utility method to generate your table columns, taking the title of the column and the function that produces the property the cell value factory needs.
E.g. you could do something like
private <S,T> TableColumn<S,T> createColumn(String title, Function<S, Property<T>> prop) {
TableColumn<S,T> column = new TableColumn<>(title);
column.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
return column ;
}
and then if your model classes use JavaFX properties, all you need is
TableColumn<SubClass1, Number> tc1Id = createColumn("Id", SubClass1::idProperty);
etc.
If you are not using JavaFX properties (which is the recommended approach), you can still do
TableColumn<SubClass2, String> tc2Loc =
createColumn("Location", item -> new SimpleStringProperty(item.getLocation()));
or just create a method that accepts a Function<S,T> instead of a Function<S,Property<T>>.
I need to add to my TreeTableView the content for two columns("Id" and "Workplace").
I don't know how to do it, because I can't get nested value from Manager -> ArrayList.
What should I pass in TreeItemPropertyValueFactory if the type of the content can be only String???
The rest of code works OK.
I will be grateful for any help.
public void showStaffInTreeTable(){
Employee emp_1 = new Employee("1", "secretary");
Employee emp_2 = new Employee("2", "cleaner");
Employee emp_3 = new Employee("3", "driver");
Employee emp_4 = new Employee("4", "mechanic");
ArrayList<Employee> johnStaff = new ArrayList<>(Arrays.asList(emp_1, emp_2));
ArrayList<Employee> amandaStaff = new ArrayList<>(Arrays.asList(emp_3, emp_4));
Manager john = new Manager("John", johnStaff);
Manager amanda = new Manager("Amanda", amandaStaff);
TreeTableColumn<Manager, String> columnManager = new TreeTableColumn<>("Manager");
TreeTableColumn<Manager, String> columnStaffId = new TreeTableColumn<>("Id");
TreeTableColumn<Manager, String> columnStaffWorkplace = new TreeTableColumn<>("Workplace");
columnManager.setCellValueFactory(new TreeItemPropertyValueFactory<>("managersName"));
columnStaffId.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getId???"));
columnStaffWorkplace.setCellValueFactory(new TreeItemPropertyValueFactory<>
("how to pass here: Manager-> ArrayList<Employess> -> getEmployee -> getWorkplace???"));
TreeTableView<Manager> managers = new TreeTableView<>();
managers.getColumns().addAll(columnManager, columnStaffId, columnStaffWorkplace);
TreeItem managerItem_1 = new TreeItem(john);
managerItem_1.getChildren().addAll(new TreeItem<>(emp_1), new TreeItem<>(emp_2));
TreeItem managerItem_2 = new TreeItem(amanda);
managerItem_2.getChildren().addAll(new TreeItem<>(emp_3), new TreeItem<>(emp_4));
TreeItem root = new TreeItem(new Manager("", new ArrayList<>()));
root.getChildren().addAll(managerItem_1, managerItem_2);
root.setExpanded(true);
managers.setRoot(root);
}
public class Employee {
private String id;
private String workplace;
public Employee(String id, String workplace) {
this.id = id;
this.workplace = workplace;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getWorkplace() {
return workplace;
}
public void setWorkplace(String workplace) {
this.workplace = workplace;
}
}
public class Manager {
private String managersName;
private List<Employee> managersStaff = new ArrayList<>();
public Manager(String managersName, List<Employee> managersStaff) {
this.managersName = managersName;
this.managersStaff = managersStaff;
}
public String getManagersName() {
return managersName;
}
public void setManagersName(String managersName) {
this.managersName = managersName;
}
public List<Employee> getManagersStaff() {
return managersStaff;
}
public void setManagersStaff(List<Employee> managersStaff) {
this.managersStaff = managersStaff;
}
}
You can do
columnStaffId.setCellValueFactory(cellData -> {
TreeItem<?> item = cellData.getValue();
Object data = item.getValue();
if (data instanceof Employee) {
Employee employee = (Employee)data ;
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Note in Java 14 you can simplify this to
columnStaffId.setCellValueFactory(cellData -> {
if (cellData.getValue().getValue() instanceof Employee employee) {
return new SimpleStringProperty(employee.getId());
} else {
return new SimpleStringProperty("");
}
});
Your setup is a little weird, as you declare a TreeTableView<Manager> but some of the items don't contain Managers, but Employees. So there's no real guarantee you don't get ClassCastExceptions thrown in places here, or other errors caused by the TreeItemPropertyValueFactory trying to call getManagersName() on an object that isn't a Manager.
You might want to refactor so you use a TreeTableView<Object>, or maybe refactor the model so that Manager and Employee are both subclasses of some other class (which you then use as the type for your TreeTableView).
I am trying to build a JavaFX Application to display a TreeTableView. Still setting up this whole thing. I got it to work with only one column without the Product class but i am struggling to make it work with the Product class and two columns. The following piece of code fails to compile:
col1.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getNameProperty());
and spits out this error:
Error:(38, 121) java: incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to javafx.beans.value.ObservableValue<java.lang.String>
This is the entire code:
public class Controller implements Initializable {
#FXML
private TreeTableView<Product> tableView;
#FXML
private TreeTableColumn<Product, String> col1;
#FXML
private TreeTableColumn<Product, String> col2;
TreeItem<Product> product1 = new TreeItem<>(new Product("Bread", "300g"));
TreeItem<Product> product2 = new TreeItem<>(new Product("Eggs", "5"));
TreeItem<Product> product3 = new TreeItem<>(new Product("Brad Pitt", "One and Only one"));
TreeItem<Product> product4 = new TreeItem<>(new Product("Moisturizer", "20"));
TreeItem<Product> product5 = new TreeItem<>(new Product("Horse Lubricant", "4"));
TreeItem<Product> root = new TreeItem<>(new Product("Name", "Quantity"));
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
root.getChildren().setAll(product1, product2, product3, product4, product5);
col1.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getNameProperty());
col2.setCellValueFactory(
(TreeTableColumn.CellDataFeatures<Product, String> param) -> param.getValue().getValue().getQuantityProperty());
tableView.setRoot(root);
tableView.setShowRoot(false);
}
public class Product{
SimpleStringProperty nameProperty;
SimpleStringProperty quantityProperty;
public Product(String name, String quantity){
this.nameProperty = new SimpleStringProperty(name);
this.quantityProperty = new SimpleStringProperty(quantity);
}
public String getNameProperty() {
return nameProperty.get();
}
public SimpleStringProperty namePropertyProperty() {
return nameProperty;
}
public void setNameProperty(String nameProperty) {
this.nameProperty.set(nameProperty);
}
public String getQuantityProperty() {
return quantityProperty.get();
}
public SimpleStringProperty quantityPropertyProperty() {
return quantityProperty;
}
public void setQuantityProperty(String quantityProperty) {
this.quantityProperty.set(quantityProperty);
}
}
}
First, your Product class is not conventional. Typically the field name matches the property name (e.g. name, not nameProperty). Then you name your getter, setter, and property getter after the name of the property. For instance:
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;
public class Product {
private final StringProperty name = new SimpleStringProperty(this, "name");
public final void setName(String name) { this.name.set(name); }
public final String getName() { return name.get(); }
public final StringProperty nameProperty() { return name; }
private final StringProperty quantity = new SimpleStringProperty(this, "quantity");
public final void setQuantity(String quantity) { this.quantity.set(quantity); }
public final String getQuantity() { return quantity.get(); }
public final StringProperty quantityProperty() { return quantity; }
public Product() {} // typically Java(FX)Beans provide no-arg constructors as well
public Product(String name, String quantity) {
setName(name);
setQuantity(quantity);
}
}
Note: Your class is a non-static nested (i.e. inner) class. This means each Product instance requires an instance of the enclosing class. If you want to keep Product a nested class, consider making it static. My example above assumes Product is in its own source file.
With that class, you would define your cell value factories like so:
TreeTableColumn<Product, String> nameCol = ...;
nameCol.setCellValueFactory(data -> data.getValue().getValue().nameProperty());
TreeTableColumn<Product, String> quantityCol = ...;
quantityCol.setCellValueFactory(data -> data.getValue().getValue().quantityProperty());
Notice the factories return the appropriate property of the Product instance. This solves your compilation error since StringProperty is an instance of ObservableValue<String>. It also means your table has direct access to the backing model's property, which helps with keeping the table up-to-date and also with implementing inline editing.
In case it helps, here's setting the cell value factory of nameCol using an anonymous class which explicitly shows all the types used:
nameCol.setCellValueFactory(new Callback<>() { // may have to explicitly define type arguments, depending on version of Java
#Override
public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<Product, String> data) {
TreeItem<Product> treeItem = data.getValue();
Product product = treeItem.getValue();
return product.nameProperty();
}
});
In the JavaFx ComboBox which uses a class object list .I want to select items in the ComboBox programmatically using getSelectionModel().select(object or index). i am not getting the desired result Although the value is set but it is something like this main.dao.Company.Company.CompanyTableData#74541e7b.
The code is somewhat like this.
ComboBox<CompanyTableData> company = new ComboBox<>();
company.setItems(GetCompany.getCompanyTableData());//where Observable list is set..
GetCompany.getCompanyTableData() returns observablelist of CompanyTableData class.
The ComboBox Looks as follows.
The CompanyTableData Class is as.
public class CompanyTableData {
private SimpleStringProperty itemCompanyId;
private SimpleStringProperty itemCompanyName;
private SimpleStringProperty createBy;
private SimpleStringProperty createdOn;
public CompanyTableData(CompanyData companyData){
this.itemCompanyId = new SimpleStringProperty(companyData.getItemCompanyId());
this.itemCompanyName = new SimpleStringProperty(companyData.getItemCompanyName());
this.createBy = new SimpleStringProperty(companyData.getCreatedBy());
this.createdOn = new SimpleStringProperty(companyData.getCreatedOn());
}
public String getItemCompanyId() {
return itemCompanyId.get();
}
public SimpleStringProperty itemCompanyIdProperty() {
return itemCompanyId;
}
public void setItemCompanyId(String itemCompanyId) {
this.itemCompanyId.set(itemCompanyId);
}
public String getItemCompanyName() {
return itemCompanyName.get();
}
public SimpleStringProperty itemCompanyNameProperty() {
return itemCompanyName;
}
public void setItemCompanyName(String itemCompanyName) {
this.itemCompanyName.set(itemCompanyName);
}
public String getCreateBy() {
return createBy.get();
}
public SimpleStringProperty createByProperty() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy.set(createBy);
}
public String getCreatedOn() {
return createdOn.get();
}
public SimpleStringProperty createdOnProperty() {
return createdOn;
}
public void setCreatedOn(String createdOn) {
this.createdOn.set(createdOn);
}
}
The Cell Factory is set
company.setCellFactory(param -> new CompanyCell());
And the CompanyCell
public class CompanyCell extends ListCell<CompanyTableData> {
#Override
protected void updateItem(CompanyTableData item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null || item.getItemCompanyName() == null) {
setText(null);
} else {
setText(item.getItemCompanyName());
}
}
}
After all this when i try to set the items programmetically as
company.getSelectionModel().select(getSelectedCompanyIndex());
The getSelectedCompanyIndex() function is as follows.
public static CompanyTableData getSelectedCompanyIndex(){
CompanyTableData c = null,i;
Iterator<CompanyTableData> itr = GetCompany.getCompanyTableData().iterator();
while (itr.hasNext()){
i = itr.next();
if (i.getItemCompanyName().equals(Element.getItemTableData().getCompany())){
c = i;
}
}
return c;
}
And the result i am getting is
And
At the end it should select a name or item in the list but it has set some type of object i think.
Now what should i do. Is there any type of string conversion required.
The buttonCell used to display the item when the combobox popup is not shown is not automatically created using the cellFactory. You need to set this property too to use the same cell implementation:
company.setCellFactory(param -> new CompanyCell());
company.setButtonCell(new CompanyCell());
Ok, so I know this is a common problem that has been posted about a lot but as much as I try to follow the advice given, my TableView till displays no data... I'll reduce my object a bit to keep things as short as possible. Here is my Object:
public SimpleStringProperty itemCode, itemName;
public ResourceItem(String code, String name) {
this.itemCode = new SimpleStringProperty(code);
this.itemName = new SimpleStringProperty(name);
}
public String getItemCode() {
return itemCode.get();
}
public void setItemCode(String code) {
itemCode.set(code);
}
public SimpleStringProperty itemCodeProperty() {
return itemCode;
}
public SimpleStringProperty itemNameProperty() {
return itemName;
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String name) {
itemName.set(name);
}
And here is where I create the TableColumns:
TableColumn<ResourceItem, String> code = new TableColumn("Item Code");
code.setCellValueFactory(new PropertyValueFactory("itemCode"));
TableColumn<ResourceItem, String> code = new TableColumn("Item Name");
name.setCellValueFactory(new PropertyValueFactory("itemName"));
I add Resource Items to the ObservableList through a for loop and set my items of the TableView to that list:
ObservableList<ResourceItem> data = FXCollections.observableArrayList();
....
itemsInDB.setItems(data);
itemsInDB.getColumns().addAll(code, name);
And then nothing is added. Can someone help me out please?
EDIT:
Here is a testable version. It does require you set up a database called ims, a table called im_resoureitem_br with two columns: IMItemCode Varchar(4) and IMItemName Varchar(30).
public class TableViewTest extends Application {
final String DRIVER = "com.mysql.jdbc.Driver";
String urlHead = "jdbc:mysql://localhost/ims";
final String USER = "root";
final String PASS = "";
Connection connection;
Statement statement;
private TableView<ResourceItem> table = new TableView<ResourceItem>(); //creates table to hold Course objects
private final ObservableList<ResourceItem> data
= FXCollections.observableArrayList();
#Override
public void start(Stage stage) throws ClassNotFoundException {
Scene scene = new Scene(new Group());
stage.setTitle("Fall 2015 Schedule"); //title of stage, appears at top bar
stage.setWidth(700);
stage.setHeight(500);
final Label label = new Label("Brenna Morss-Fish Fall Schedule 2015");
table.setEditable(true);
table.setItems(data); //sets rows of table as data from course arraylist
TableColumn<ResourceItem, String> code = new TableColumn<ResourceItem, String>("Code:");//creates first column
code.setMinWidth(100);
code.setCellValueFactory(
new PropertyValueFactory("itemCode"));
TableColumn<ResourceItem, String> name = new TableColumn<ResourceItem, String>("Name:");//creates first column
name.setMinWidth(100);
name.setCellValueFactory(
new PropertyValueFactory("itemName")); //defines what column holds according to name field of Course class
String query = "select * from ims.im_resourceItem_br; ";
ArrayList<String[]> items = new ArrayList<String[]>();
TableView<ResourceItem> itemsInDB = new TableView();
items = getQueryResult(query);
//itemsInDB.setEditable(false);
ResourceItem item = new ResourceItem("", "");
ObservableList<ResourceItem> data = FXCollections.observableArrayList();
data.removeAll(data);
//System.out.println(items.get(0).toString());
for (int i = 0; i < items.size(); i++) {
item.setItemCode(items.get(i)[1]);
item.setItemName(items.get(i)[2]);
data.add(item);
}
code.setCellValueFactory(new PropertyValueFactory("itemCode"));
name.setCellValueFactory(new PropertyValueFactory("itemName"));
itemsInDB.setItems(data);
System.out.println(itemsInDB.getItems());
itemsInDB.getColumns().addAll(code, name);
table.getColumns().addAll(code, name);
//adds previously defined columns to the table in the order they will appear
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.getChildren().addAll(label, table); //adds label and course table to VBox layout container
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene); //adds scene to the stage
stage.show(); //displays stage
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ArrayList getQueryResult(String stmt) throws ClassNotFoundException {
String results = "";
ResultSet resultSet = null;
String row = "";
ArrayList<String[]> list = new ArrayList<String[]>();
try {
Class.forName(DRIVER);
connection = DriverManager.getConnection(urlHead, USER, PASS);
statement = connection.createStatement();
resultSet = statement.executeQuery(stmt);
int columnCount = resultSet.getMetaData().getColumnCount();
while (resultSet.next()) {
String delims = "[%]";
row = "";
for (int i = 1; i <= columnCount; i++) {
row += resultSet.getString(i) + "%";
}
String[] array = row.split(delims);
list.add(array);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public static class ResourceItem {
public SimpleStringProperty itemCode, itemName;
public ResourceItem(String code, String name) {
this.itemCode = new SimpleStringProperty(code);
this.itemName = new SimpleStringProperty(name);
}
public String getItemCode() {
return itemCode.get();
}
public void setItemCode(String code) {
itemCode.set(code);
}
public SimpleStringProperty itemCodeProperty() {
return itemCode;
}
public SimpleStringProperty itemNameProperty() {
return itemName;
}
public String getItemName() {
return itemName.get();
}
public void setItemName(String name) {
itemName.set(name);
}
public String toString() {
String print = itemCode + " " + itemName + " ";
return print;
}
}
}
You have created two tables: one called table, which you display in the UI when you add it to vbox, and another called itemsInDB, which you populate but never display. Since the table you do display has no data in it, and the table you populate is never displayed, you never see the data.
You have another logical error when you populate the observable list: you add the same item over and over to the list, and update its properties each time. So if it were displayed you would see the same item repeatedly in the table.
There may be other errors I haven't noticed, but since you haven't created a MCVE, I can't actually run it and test it.