How to use SimpleIntegerProperty in JavaFX - javafx

I tried to populate a tableView, I followed the tutorial given in docs.oracle, but in my table there are Integer fields, so I do the same thing to add them.
The code in the information class (like Person class):
private SimpleIntegerProperty gel;
public int getGel() {
return gel.get();
}
public void setGel(int pop) {
gel.set(pop);
}
The code in the Main class:
TableColumn gel = new TableColumn("Gel");
gel.setMinWidth(100);
gel.setCellValueFactory(new PropertyValueFactory<Information, Integer>("gel"));
gel.setCellFactory(TextFieldTableCell.forTableColumn());
gel.setOnEditCommit(new EventHandler<CellEditEvent<Information, Integer>>() {
#Override
public void handle(CellEditEvent<Information, Integer> t) {
((Information) t.getTableView().getItems()
.get(t.getTablePosition().getRow()))
.setGel(t.getNewValue());
}
});
but I have errors:
Caused by: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at javafx.util.converter.DefaultStringConverter.toString(DefaultStringConverter.java:34)
at javafx.scene.control.cell.CellUtils.getItemText(CellUtils.java:100)
at javafx.scene.control.cell.CellUtils.updateItem(CellUtils.java:201)
at javafx.scene.control.cell.TextFieldTableCell.updateItem(TextFieldTableCell.java:204)

The problem is in your cell factory.
TableColumn should be typed to TableColumn<Information, Integer>. Then you will see an error here:
gel.setCellFactory(TextFieldTableCell.forTableColumn());
(the same error you have on runtime). The reason is the static callback forTableColumn is only for TableColumnof type String.
For other types you have to provide a custom string converter. This will solve your problems:
gel.setCellFactory(TextFieldTableCell.forTableColumn(new StringConverter<Integer>(){
#Override
public String toString(Integer object) {
return object.toString();
}
#Override
public Integer fromString(String string) {
return Integer.parseInt(string);
}
}));

Related

Populate Tableview with super class fields

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

How to use groupingBy of stream API for multi level nested classes?

I have a list of Student objects List<Student> allStudents from which I need to find out which student gained how much score per course and task using Java 8 stream API. I came across some older posts like this one but couldn't apply to my problem.
Below are my nested classes:
public class Student{
private long studentId;
private List<Course> courses;
public long getStudentId() {
return studentId;
}
public List<Course> getCourses() {
return courses;
}
}
public class Course{
private long courseId;
private List<Task> tasks;
public long getCourseId() {
return courseId;
}
public List<Task> getTasks() {
return tasks;
}
}
public class Task{
private long taskId;
private List<Assessment> assessments;
public long getTaskId() {
return taskId;
}
public List<Assessment> getAssessments() {
return assessments;
}
}
public class Assessment{
private String type;
private double score;
public String getType() {
return type;
}
public double getScore() {
return score;
}
}
Somehow multi level grouping couldn't work for me. Could anyone guide me on this ?
As you mentioned in the old question you referenced, can use the flat map approach where each nesting level is flat mapped down to the level required as follows:
Map<Triple<Long, Long, Long>, Double> result = allStudents.stream()
.flatMap(s -> s.getCourses().stream().map(
c -> ImmutableTuple.of(s.getStudentId(), c)))
.flatMap(sc -> sc.get().getTasks().stream().map(
t -> ImmutableTuple.of(sc.getFirst(), sc.get().getCourseId(), t)))
.flatMap(sct -> sct.get().getAssessments().stream().map(
a -> ImmutableTuple.of(sct.getFirst(), sct.getSecond(), sct.get().taskId, a.getScore())))
.collect(Collectors.groupingBy(
ImmutableQuadruple::remove,
Collectors.summingDouble(ImmutableQuadruple::get)
));
Note: This is using tuples from the typedtuples library

Reflection issue: NoSuchMethodException <init> ...specification.SearchCriteria, [Ljava.lang.String;)

Well, NoSuchMethodException is normally well self-explaining. Unfortunately, in my case, I couldn't even guess why I am getting such error.
I am taking care a code from other developer and I must maintain it. It was designed with specification pattern in mind. In order to make the search engine very generic, basically, any string passed from client to rest service is split in order to build the search criteria.
When executing "clazzSpec.getDeclaredConstructor(SearchCriteria.class, String[].class).newInstance(param);" I get
java.lang.NoSuchMethodException: br.com.mycompany.specification.SomethingSpecification.<init>(br.com.mycompany.specification.SearchCriteria, [Ljava.lang.String;)
Looking the image bellow, I can't see what is missed
SearchCriteria:
public class SearchCriteria {
private String key;
private String operation;
private Object value;
public SearchCriteria(String key, String operation, Object value) {
this.key = key;
this.operation = operation;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
SomethingSpecification
public class SomethingSpecification extends Specification<Something> {
public SomethingSpecification(SearchCriteria criteria) {
super(criteria);
}
#Override
public Predicate toPredicate(Root<Something> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
switch (criteria.getOperation()) {
case "=":
...
}
return super.toPredicate(root, query, builder);
}
}
The reflection code looks for a constructor with two arguments: SearchCriteria and a String[]. But the only constructor for SomethingSpecification only has one argument.

Error Showing as Class Cast Exception while changing the value of combobox in Javafx

On selection of Tableview row, it display the data in the combobox,
i try to display the value in the comboxbox from tableview using this code.
private void showInputDetails(InputConfigurationModel ipmodel) {
if (ipmodel != null) {
cmbfiletype.setValue(ipmodel.getFiletype().toString());
}
My Inputconfiguartion Model class:
public class InputConfigurationModel {
public StringProperty filetype = new SimpleStringProperty();
public InputConfigurationModel(String filetype) {
this.filetype = new SimpleStringProperty(filetype);
}
public InputConfigurationModel() {
}
public String getFiletype() {
return filetype.get();
}
public void setFiletype(String value) {
filetype.set(value);
}
public StringProperty filetypeProperty()
{
return filetype;
}
// #Override
// public String toString() {
// return filetype.toString(); //To change body of generated methods, choose Tools | Templates.
// }
}
but if i try change the value of combobox for update it display error as
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: java.lang.String cannot be cast to Clover.Converter.Model.ExtensionModel
i am trying to change the value in the combobox from this code
Loading the combobox value from this Loadfile method
public void LoadFile() {
try {
String sql = "select * from EXTENSION";
PreparedStatement ps = conn.prepareStatement(sql);
rs = ps.executeQuery(sql);
while (rs.next()) {
ExtensionModel extModel = new ExtensionModel();
filetypelstupdate_ip = FXCollections.observableArrayList(extModel);
String ext_type = rs.getString("EXT_TYPE");
String ext_name = rs.getString("EXT_NAME");
int ext_id=Integer.parseInt(rs.getString("EXT_ID"));
extModel.setExttype(ext_type);
extModel.setExtname(ext_name);
extModel.setExtid(ext_id);
cmbfiletype.getItems().addAll(filetypelstupdate_ip);
cmbfiletype.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ExtensionModel>() {
#Override
public void changed(ObservableValue<? extends ExtensionModel> observable, ExtensionModel oldValue, ExtensionModel newValue) {
aaa(newValue);
}
});
catch (Exception ex) {
ex.printStackTrace();
}
}
public void aaa(ExtensionModel exm){
if(cmbfiletype!=null)
{
txtextid.setText(exm.getExtid().toString());
System.out.println("txtextid"+txtextid);
}
}
i dont how to solve this error? tried everything but still coming class cast exception
my error is coming in LoadFile Method in this code first line
**cmbfiletype.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ExtensionModel>() {**
#Override
public void changed(ObservableValue<? extends ExtensionModel> observable, ExtensionModel oldValue, ExtensionModel newValue) {
aaa(newValue);
});
}
} catch (Exception e) {
e.printStackTrace();
}
First it display the value in the comboxbox from the tableview which is a string in INPUTCONFIGURATION model class and thn i tried to change the the combobox value which comes from LoadFile method, hence it comes as class cast exception. kindly help me how to solve this class cast exception error.

How to make TableCell editable , so it automatically updates the data class?

I am making a system for a school project , and one part of it is a TableView that is populated with rows using my own data class InventoryData that has properties correspondent to the table columns. I would like to make cells in some columns editable using a TextField, so that when an edit is committed, it will update the InventoryData object's relevant property.
I tried setting TextFieldTableCell.forTableColumn() as the cell factory of the columns. Although, now after committing the edit, the text in the cell will change, I don't think it is changing the property in the InventoryData object. The reason why I think that, is because when I try to edit that cell again ( after already being edited once), the TextField shows the former value ( before the first edit).
Did I do something wrong , or is that normal behavior and I have to implement the commits myself?
Here's the code for InventoryData :
package UILayer.TableData;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import ModelLayer.Product;
public class InventoryData {
// From Product
private Product productObj;
private SimpleIntegerProperty id;
private SimpleStringProperty name;
// Constructor - converts Product obj into InventoryData
public InventoryData(Product product)
{
this.productObj = product;
this.id = new SimpleIntegerProperty(product.getId());
this.name = new SimpleStringProperty(product.getName())
}
// GET & SET
public Product getProduct()
{
return productObj;
}
public int getId() {
return id.get();
}
public void setId(int id) {
this.id.set(id);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
productObj.setName(name);
System.out.println(productObj.getName());
}
}
You need your InventoryData class to use the JavaFX Properties pattern. Specifically it needs property-type accessor methods in order to retrieve the property in the table cells. Without this, the cell value factory just calls the standard getName() or getId() method, and wraps the result in a ReadOnlyStringWrapper (or ReadOnlyIntegerWrapper): the table cell cannot change the values of those wrappers (since they are read only).
public class InventoryData {
// From Product
private Product productObj;
private IntegerProperty id;
private StringProperty name;
// Constructor - converts Product obj into InventoryData
public InventoryData(Product product)
{
this.productObj = product;
this.id = new SimpleIntegerProperty(product.getId());
this.name = new SimpleStringProperty(product.getName())
this.name.addListener((obs, oldName, newName) ->
productObj.setName(newName));
}
// GET & SET
public Product getProduct()
{
return productObj;
}
public IntegerProperty idProperty() {
return id ;
}
public final int getId() {
return idProperty().get();
}
public final void setId(int id) {
idProperty().set(id);
}
public StringProperty nameProperty() {
return name ;
}
public final String getName() {
return nameProperty().get();
}
public final void setName(String name) {
this.nameProperty().set(name);
// productObj.setName(name);
// System.out.println(productObj.getName());
}
}

Resources