TreeTableView add nested value to TreeItemPropertyValueFactory - javafx

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).

Related

Query with DynamoDB Secondary Index AWS SDK 2 Java exception creating DynamoDbIndex object

I'm having trouble running a query against a secondary index, getting an exception:
Ex getting dynamodb scan: java.lang.IllegalArgumentException: Attempt to execute an operation that requires a secondary index without defining the index attributes in the table metadata. Index name: category-timestamp-index
Can someone guide me on how I'm doing this wrong?
My table is idIT_RSS_Sources and I've created an index category-timestamp-index.
screenshot attached of index
My code is:
DynamoDbEnhancedClient enhancedClient = getEnhancedDBClient(region);
// Create a DynamoDbTable object
logger.debug("getting RSS Source category-timestamp-index");
//this throws the exception
DynamoDbIndex<RSS_Source> catIndex =
enhancedClient.table("idIT_RSS_Sources",
TableSchema.fromBean(RSS_Source.class))
.index("category-timestamp-index");
logger.debug("building query attributes");
AttributeValue att = AttributeValue.builder()
.s(theCategory)
.build();
Map<String, AttributeValue> expressionValues = new HashMap<>();
expressionValues.put(":value", att);
Expression expression = Expression.builder()
.expression("category = :value")
.expressionValues(expressionValues)
.build();
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder().partitionValue(theCategory)
.build());
logger.debug("calling catIndex.query in getRSS...ForCategory");
Iterator<Page<RSS_Source>> dbFeedResults = (Iterator<Page<RSS_Source>>) catIndex.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
solved, I was not using the proper annotation in my model class:
#DynamoDbSecondaryPartitionKey(indexNames = { "category-index" })
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
Assume you have a model named Issues.
package com.example.dynamodb;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
#DynamoDbBean
public class Issues {
private String issueId;
private String title;
private String createDate;
private String description;
private String dueDate;
private String status;
private String priority;
private String lastUpdateDate;
#DynamoDbPartitionKey
public String getId() {
return this.issueId;
}
public void setId(String id) {
this.issueId = id;
}
#DynamoDbSortKey
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public void setLastUpdateDate(String lastUpdateDate) {
this.lastUpdateDate = lastUpdateDate;
}
public String getLastUpdateDate() {
return this.lastUpdateDate;
}
public void setPriority(String priority) {
this.priority = priority;
}
public String getPriority() {
return this.priority;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return this.status;
}
public void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
#DynamoDbSecondaryPartitionKey(indexNames = { "dueDateIndex" })
public String getDueDate() {
return this.dueDate;
}
public String getDate() {
return this.createDate;
}
public void setDate(String date) {
this.createDate = date;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
}
Notice the annotation on getDueDate.
#DynamoDbSecondaryPartitionKey(indexNames = { "dueDateIndex" })
public String getDueDate() {
return this.dueDate;
}
This is because the Issues table has a secondary index named dueDateIndex.
To query on this secondary index, you can use this code that uses the Amazon DynamoDB Java API V2:
public static void queryIndex(DynamoDbClient ddb, String tableName, String indexName) {
try {
// Create a DynamoDbEnhancedClient and use the DynamoDbClient object
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
//Create a DynamoDbTable object based on Issues
DynamoDbTable<Issues> table = enhancedClient.table("Issues", TableSchema.fromBean(Issues.class));
String dateVal = "2013-11-19";
DynamoDbIndex<Issues> secIndex =
enhancedClient.table("Issues",
TableSchema.fromBean(Issues.class))
.index("dueDateIndex");
AttributeValue attVal = AttributeValue.builder()
.s(dateVal)
.build();
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder().partitionValue(attVal)
.build());
// Get items in the Issues table
SdkIterable<Page<Issues>> results = secIndex.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.set(0);
results.forEach(page -> {
Issues issue = (Issues) page.items().get(atomicInteger.get());
System.out.println("The issue title is "+issue.getTitle());
atomicInteger.incrementAndGet();
});
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
For what it's worth, if your Global Secondary Index has a sort key, you must annotate that field in the DynamoDB bean with:
#DynamoDbSecondarySortKey(indexNames = { "<indexName>" })
public String getFieldName() {
return fieldName;
}
My working code is as below:
sortKey-index = GSI in dynamo db
List<Flow> flows = new ArrayList<>();
DynamoDbIndex<Flow> flowBySortKey = table().index("sortKey-index");
// Create a QueryConditional object that's used in the query operation
QueryConditional queryConditional = QueryConditional
.keyEqualTo(Key.builder()
.partitionValue(sortKey)
.build());
SdkIterable<Page<Flow>> dbFeedResults = flowBySortKey.query(
QueryEnhancedRequest.builder()
.queryConditional(queryConditional)
.build());
dbFeedResults.forEach(flowPage -> {
flows.addAll(flowPage.items());
});

JavaFX TreeTableView - Prevent editing of unavailable cells

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.

JavaFX Binding entire model to form

I spent full day to make my model observable by this JavaFx databinding.
At this point I already see, that if I change one property like this, it works like charm
selectedTestcase.setFolder("....");
but how I can observe the following and refresh my form:
if (maybeCase.isPresent()) {
selectedTestcase = maybeCase.get();
}
So I change the complete model. How I can make this?
Model:
#XmlRootElement(name = "Testcase")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Testcase {
private StringProperty Guid;
#XmlElement(name="GUID")
public String getGuid() {
return guidProperty().get();
}
public StringProperty guidProperty() {
if (Guid == null)
Guid = new SimpleStringProperty(this, "Guid");
return Guid;
}
public void setGuid(String guid) {
this.guidProperty().set(guid);
}
private StringProperty caseName;
#XmlElement(name="CaseName")
public String getCaseName() {
return caseNameProperty().get();
}
public StringProperty caseNameProperty() {
if (caseName == null)
caseName = new SimpleStringProperty();
return caseName;
}
public void setCaseName(String caseName) {
this.caseNameProperty().set(caseName);
}
ViewModel:
public Testcase selectedTestcase = new Testcase();
public void setSelectedTestcase(String folder, String filename) {
Optional<Testcase> maybeCase = this.AvailableTestCases.stream()
.filter((t -> t.TestcaseEqualsFolderAndName(folder, filename))).findFirst();
if (maybeCase.isPresent()) {
selectedTestcase = maybeCase.get();
}
}
Thanks in advance :)
Thanks to James_D and the Easybind Library:
MonadicObservableValue
That seems to be the solution:
private ObjectProperty<Testcase> testcaseObjectProperty = new SimpleObjectProperty<>(new Testcase());
public MonadicObservableValue<Testcase> selectedTestcase = EasyBind.monadic(testcaseObjectProperty);
public void setSelectedTestcase(String folder, String filename) {
Optional<Testcase> maybeCase = this.AvailableTestCases.stream()
.filter((t -> t.TestcaseEqualsFolderAndName(folder, filename))).findFirst();
if (maybeCase.isPresent()) {
testcaseObjectProperty.setValue(maybeCase.get());
}
}
and then the final binding:
txtCaseName.textProperty().bind(viewModel.selectedTestcase.flatMap(Testcase::caseNameProperty).orElse(""));
James; you are able to explain me this "orElse"?

No content displayed when populating TableView with attributes of an Object

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.

JavaFX - Incompatible parameter type with using TreeView.EditEvent in lambda

In a JavaFX TreeView I'm using 'custom' classes which extend TreeItem. This makes me able to edit the items in the TreeView (I can double click them and edit the contents when running the application) but I can't seem to be able to set the .setOnEditCommit() method properly. I was hoping it'd work similar as the function in a tableview but I didn't have any luck yet.
This is my code in my controller in which I try to set the setOnEditCommit() method. In my TreeView called 'trvDivisies' I display football team divisions / competitions and one level lower I display all the teams that are in a certain division.
private void setUpTreeView() {
trvDivisies.setEditable(true);
trvDivisies.setShowRoot(false);
TreeItem<String> root = new TreeItem<>();
for (Divisie d : divisies) {
TreeItem<String> divisieTreeItem = d;
divisieTreeItem.valueProperty().set(d.getNaam());
for (VoetbalTeam vt : d.getVoetbalTeams()) {
TreeItem<String> voetbalTeamTreeItem = vt;
voetbalTeamTreeItem.valueProperty().setValue(vt.getTeamNaam());
divisieTreeItem.getChildren().add(voetbalTeamTreeItem);
}
root.getChildren().add(divisieTreeItem);
}
trvDivisies.setRoot(root);
trvDivisies.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
System.out.println(newValue);
}
});
trvDivisies.setCellFactory(TextFieldTreeCell.forTreeView());
// I get an error at the following line when compiling
trvDivisies.setOnEditCommit((TreeView.EditEvent p) -> {
TreeItem<String> selectedItem = p.getTreeItem();
if (selectedItem instanceof Divisie) {
updateDivisie((Divisie)selectedItem);
} else if (selectedItem instanceof VoetbalTeam) {
updateTeam((VoetbalTeam)selectedItem);
}
});
}
This is what my 'custom' classes look like.
public class Divisie extends TreeItem<String> {
private static int idCount = 0;
private int id;
private String naam;
private List<VoetbalTeam> voetbalTeams;
public int getId() {
return id;
}
public String getNaam() {
return naam;
}
public List<VoetbalTeam> getVoetbalTeams() {
return voetbalTeams;
}
public Divisie(int id, String naam) {
super(naam);
this.id = id;
this.naam = naam;
}
public Divisie(String naam) {
this.id = ++idCount;
this.naam = naam;
}
public void addTeam(VoetbalTeam toBeAdded) {
if (voetbalTeams == null) {
voetbalTeams = new LinkedList<>();
}
voetbalTeams.add(toBeAdded);
}
#Override
public String toString() {
return this.naam;
}
}
Second 'lower level' class
public class VoetbalTeam extends TreeItem<String> {
private static int idCount = 0;
private int id;
private String teamNaam;
private List<Speler> spelers;
public int getId() {
return id;
}
public String getTeamNaam() {
return teamNaam;
}
public List<Speler> getSpelers() {
return this.spelers;
}
public VoetbalTeam(int id, String teamNaam) {
super(teamNaam);
this.id = id;
this.teamNaam = teamNaam;
}
public VoetbalTeam(String teamNaam) {
super(teamNaam);
this.id = ++idCount;
this.teamNaam = teamNaam;
}
public void addSpeler(Speler nieuweSpeler) {
if (spelers == null) {
spelers = new LinkedList<>();
}
this.spelers.add(nieuweSpeler);
}
#Override
public String toString() {
return this.teamNaam;
}
}
When trying to run the application WITH the .setOnEditCommit() method I get an error saying:
Error:(97, 37) java: incompatible types: incompatible parameter types in lambda expression
I was hoping you guys can tell me what I need to change my TreeView.EditEvent lambda to or help me find an easier solution.
For a TreeView<T>, the signature of setOnEditCommit is
void setOnEditCommit(EventHandler<TreeView.EditEvent<T>> value)
Since you have (apparently) a TreeView<String>, you need
trvDivisies.setOnEditCommit((TreeView.EditEvent<String> p) -> {
// ...
});
Or, of course, you can just let the compiler do the work for you:
trvDivisies.setOnEditCommit(p -> {
// ...
});

Resources