Using RowFilter with ArrayList - java

I have tried my best to look at all docs and javadoc for the RowFilter. I am using an array list of objects and I have a AbstractTableModel for my JTable. I want to filter the JTable to only show the object(s) date property where it is after a certain date.
Is the AbstractTableModel used as the argument to the includes method? This is the example from the documentation.
RowFilter<PersonModel,Integer> ageFilter = new RowFilter<PersonModel,Integer>() {
public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) {
PersonModel personModel = entry.getModel();
Person person = personModel.getPerson(entry.getIdentifier());
if (person.getAge() > 20) {
// Returning true indicates this row should be shown.
return true;
}
// Age is <= 20, don't show it.
return false;
}
};
Is it possible to get an explanation of this includes method and some way of adapting it to my situation. I understand how to compare dates, but how does the method access the row and object in my JTable?

Okay, it's really very simply...once you've done it few times ;)
RowFilter<PersonModel, Integer> ageFilter = new RowFilter<PersonModel, Integer>() {
Obviously defines the constraints of the RowFilter, basically, it defines the "row model" (PersonModel) and the method of referencing the each row (Integer)
Basically, it says, "I have a TableModel which can be accessed via a Integer value"...
public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) {
Is the only abstract method that needs to be implemented ;)
PersonModel personModel = entry.getModel();
Gets the model from the entry
Person person = personModel.getPerson(entry.getIdentifier());
Basically, this gets the Person from the model using the row index as specified by entry.getIdentifier()
if (person.getAge() > 20) {
// Returning true indicates this row should be shown.
return true;
}
// Age is <= 20, don't show it.
return false;
Okay, that's pretty basic ;)...
Now, without any more information to go about your specific implementation, this is a REALLY basic example of what you "might" be able to do...
To make life easier, I simply wrapped it all up in a simple class, basically, when needed, you would create a new instance, passing the Date value to it and then setting the table's RowSorter filter with it...
public class DateRowFilter exetends RowFilter<TableModel, Integer>() {
private Date date;
public DateRowFilter(Date date) {
this.date = date;
}
public Date getDate() {
return date;
}
public boolean include(Entry<? extends TableModel, ? extends Integer> entry) {
boolean include = false;
TableModel model = entry.getModel();
int row = entry.getIdentifier();
for (int col = 0; col < model.getColumnCount(); col++) {
Object value = model.getValueAt(row, col);
// Make decisions here
// You'll probably want to use Date#isBefore or Date#isAfter
// depending on which side you are comparing
}
return false;
}
}

Related

Sort Array list of objects based on object attributes

I have list which contains a property class object, In the list i have 3 status
not_paid
paid
part_paid
I want to sort my list below mentioned order.
First - not_paid
second- part_paid
third -paid
How can I sort my list using Comparator class.?
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("not_paid"))) {
return -1;
}
if (p1.equals("not_paid") && p2.equals("not_paid")) {
return -1;
}
return 1;
}
};
This is my Code. i am getting below order using this code.
paid-->not_paid-->part_paid
This is my Update Code. I got my result.
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("paid"))) {
return -1;
}
if (p1.equals("part_paid") && p2.equals("paid")) {
return -1;
}
return 1;
}
};
To avoid complex comparator, I encourage you to export your statuses to an enum. (Plus this will work if you will add more statuses in the future, without the need to change logic in your comparator):
enum PaymentStatus { // Write them in order you want to be sorted
NOT_PAID,
PART_PAID,
PAID
}
Then sorting will be as simple as :
list.sort(Comparator.comparing(item ->item.getAttributes().getFieldPaymentStatus()));
What you can do is first mapping the strings to integers in the desired order, and then simply subtracting them from eachother.
private static Comparator<Payments> comparator = new Comparator<Payments>() {
// Use this mapping function to map the statuses to ints.
// The lowest number comes first
private int map(String str) {
switch (str) {
case "not_paid":
return 0;
case "part_paid":
return 1;
case "paid":
return 2;
default:
return 3;
}
}
// Alternatively, you can use the Map interface to define the sorting
// order.
#Override
public int compare(Payments o1, Payments o2) {
return map(o1.status) - map(o2.status);
}
};
I suggest – Schidu Luca already mentioned it in his answer – that you use enums to define a fixed set of known values, like payment statuses. This provides compile-time safety.
Note: I wouldn't, however, suggest to bind the enum declaration order to the sorting order.

Java: order a JTable according to columns from enum

I have a JTable where several columns contain a number from an enums like the following:
public static enum IMPORT_CONF_OPERATION_RESULT {
OK(0, "OK"),
ERROR(1, "ERROR"),
WAITING(2, "WAITING");
/* ... */
}
So, I needed to override method getValueAt() of table model looping through enum values in order to decode and return the correspondent String for each row as, in the database from which data come from, the numeric values are stored.
Now, if the user clicks on the correspondent header column, row are sorted according to numeric values but I would like to order them in alphabetical order. Shall I override sort() method of table model? Isn't looping so many times through enum values to get the description inefficient? Would it slow down table rendering?
UPDATE
This could be a solution following to what STaefi suggested, inside my extended DefaultTableModelField:
#Override
public void sort(int col, boolean ascendest) {
ColumnProperties columnProperties = this.mapColumn.get(col);
if (COLUMN_NAME_ENTITY.equals(columnProperties.getInfo()) ||
COLUMN_OPERATION_TYPE.equals(columnProperties.getInfo()) ||
COLUMN_OPERATION_RESULT.equals(columnProperties.getInfo()) ||
COLUMN_ELABORATION_TYPE.equals(columnProperties.getInfo()) ||
COLUMN_EVENT_STATE.equals(columnProperties.getInfo())) {
Collections.sort((List<TableImportConfEvent>)this.value, new EnumColumnSorter(ascendest, columnProperties.getInfo()));
this.fireTableDataChanged();
}
else {
super.sort(col, ascendest);
}
}
private class EnumColumnSorter implements Comparator<TableImportConfEvent> {
private int ascending;
private String columnName;
public EnumColumnSorter(boolean ascendest, String columnName) {
this.ascending = ascendest ? 1 : -1;
this.columnName = columnName;
}
#Override
public int compare(TableImportConfEvent o1, TableImportConfEvent o2) {
String decodedString1 = "";
String decodedString2 = "";
if (COLUMN_NAME_ENTITY.equals(this.columnName)) {
decodedString1 = getEntityName(o1.getEntityType());
decodedString2 = getEntityName(o2.getEntityType());
}
else if (COLUMN_OPERATION_TYPE.equals(this.columnName)) {
decodedString1 = getOperationName(o1.getOperationType());
decodedString2 = getOperationName(o2.getOperationType());
}
else if (COLUMN_OPERATION_RESULT.equals(this.columnName)) {
decodedString1 = getResultName(o1.getOperationResult());
decodedString2 = getResultName(o2.getOperationResult());
}
else if (COLUMN_ELABORATION_TYPE.equals(this.columnName)) {
decodedString1 = getResultName(o1.getOperationResult());
decodedString2 = getResultName(o2.getOperationResult());
}
else if (COLUMN_EVENT_STATE.equals(this.columnName)) {
decodedString1 = getStateName(o1.getEventState());
decodedString2 = getStateName(o2.getEventState());
}
return (decodedString1.compareTo(decodedString2)) * this.ascending;
}
}
To avoid looping over the enum values for each row, you may want to create a static final HashMap<Integer,IMPORT_CONF_OPERATION_RESULT> to cache the map of values to corresponding labels and initialize it in a static block inside of your enum. Then you can have a public static String getLabelByValue(int value) to use cache and avoid O(n) for looking up the label each time.
For controlling the sort orders and sort actions you may want to go after TableRowSorter but when you have overriden the getValueAt for your model the default sorting should be sufficient. Other way is use a custom Comparator in your table model to manage the logic of sorting.

JavaFx TableView - saving edits on focus lost doesn't work if focus is given to same column

I have been pulling my hair out over this issue and cannot seem to find any logic fix.
I am attempting to save the contents of a table cell when the user clicks away. After following this tutorial I have table cells that save their edits when focus is lost except when the user clicks into the same column.
I know why the issue is happening, the commitEdit() method will return immediately if isEditing() is true (which it is when you click into the same column.
public void commitEdit(T newValue) {
if (! isEditing()) return;
...
I tried overriding the method to no avail. I can force update the cell contents but I don't know how to force edit the cell value without knowing what cell I am in.
If there is a way for me to get the field name of the cell I am in, I could use Reflection to force an update but I don't know how to get the field name or if it's even possible.
It seems all you are looking for is a way for the cell to process new (or old) values and write them back to the model. Why not just provide a callback in the form of a BiConsumer<S,T>?
public class EditingCell<S,T> extends TableCell<S,T> {
private final BiConsumer<S,T> updater ;
public EditingCell(BiConsumer<S,T> updater) {
this.updater = updater ;
}
// ....
// not really sure what this method is for:
public void commit(T val) {
S rowValue = getTableView().getItems().get(getIndex());
updater.accept(rowValue, val);
}
// wouldn't this be better?
#Override
public void commitEdit(T newValue) {
super.commitEdit(newValue);
S rowValue = getTableView().getItems().get(getIndex());
updater.accept(rowValue, val);
}
// ...
}
Then you would do things like:
TableView<Person> table = new TableView<>();
TableColumn<Person, String> firstNameColumn = new TableColumn<>("First Name");
firstNameColumn.setCellValueFactory(cellData -> cellData.getValue().firstNameProperty());
firstNameColumn.setCellFactory(col -> new EditingCell(Person::setFirstName));
After digging, I found out how to get the property name of a column. With that I went ahead and wrote some generic reflections to force update. I wrapped everything in a method commit(Object val) for ease of use. These are modifications to EditCell class used here.
Disclaimer: This only works if you use a PropertyValueFactory and follow naming conventions in your row classes. This is also very fickle code, use and modify at your own discretion.
I modified the cell to be a generic cell with public static class EditingCell<S, T> extends TableCell<S, T>. Everything else from the tutorial should still be the same, if not feel free to let me know and I'll update here accordingly.
public void commit(Object val) {
// Get the table
TableView<S> t = this.getTableView();
// Get the selected row/column
S selectedRow = t.getItems().get(this.getTableRow().getIndex());
TableColumn<S, ?> selectedColumn = t.getColumns().get(t.getColumns().indexOf(this.getTableColumn()));
// Get current property name
String propertyName = ((PropertyValueFactory) selectedColumn.getCellValueFactory()).getProperty();
// Create a method name conforming to java standards ( setProperty )
propertyName = ("" + propertyName.charAt(0)).toUpperCase() + propertyName.substring(1);
// Try to run the update
try {
// Type specific checks - could be done inside each setProperty() method
if(val instanceof Double) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, double.class);
method.invoke(selectedRow, (double) val);
}
if(val instanceof String) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, String.class);
method.invoke(selectedRow, (String) val);
}
if(val instanceof Integer) {
Method method = selectedRow.getClass().getMethod("set" + propertyName, int.class);
method.invoke(selectedRow, (int) val);
}
} catch (Exception e) {
e.printStackTrace();
}
// CommitEdit for good luck
commitEdit((T) val);
}
and then since the text field won't update, I forced an update on it in cancelEdit(). This is slightly specific to my case ( I want a default of 0.0 and only accepted values are doubles ) - modify it as needed.
#Override
public void cancelEdit() {
super.cancelEdit();
// Default value
String val = "0.0";
// Check to see if there's a value
if (!textField.getText().equals(""))
val = textField.getText();
// Set table cell text
setText("" + val);
setGraphic(null);
}

Using enum as a parameter

So, I am trying to use an enumerated data type as parameter in the place of an object being passed in. I know that a simple switch statement would work but that doesn't really seem elegant to me. I have searched and found that enums can also have actions attached to them but I'm not so clear how to use it in this case or if it is even possible, or if i am just really tired. let me try to use code to explain what I'm asking.
First I have a class with certain fields of other objects that I am basically trying to use the enums to reference. In this case I have a method that acts on one of the fields of trees, because their are multiple trees the method needs to know which tree to act on.
public class bstContactManage()
{
// fields of other objects
BST searchTreeFirstName = new BST(new ComparatorObjOne);
BST searchTreeLastName = new BST(new ComparatorObjTwo);
// and so on and so forth
public boolean modify(Contact contactToFind, BST ToFindIn, String newContactInfo)
{
Contact contUpdate = new Contact(ContactToFind)//save for readdition to tree
contUpdate.update(newContactInfo);
toFindIn.remove(contactToFind);
if(toFindIn.add(contUpdate)) return true;
else return false;
}
}
what I'm wondering or more or less pondering is how to replace the BST parameter with a an enum
i know i could use a switch statement but that doesn't seem any more effective maybe more elegant than passing it an int value and letting it go wild!
so is there a way to get method to look something like
public boolean modify(Contact contactToFind, Enum BSTType, String newContactInfo)
{
Contact contUpdate = new Contact(ContactToFind)//save for readdition to tree
contUpdate.update(newContactInfo);
BSTType.remove(contactToFind);
if(BSTType.add(contUpdate)) return true;
else return false;
}
most of my question stems from the fact that an object such as
bstContactManage man = new bstContactManage()
will be instantiated in another class, and therefore it isn't safe or doesn't seem proper to me to do something like
man.modify(contactIn, man.searchTreeFirstName, "String");
update:
so for more clarification i have another method find which searches a given BST, and currently i am implementing it like this
public List<Contact> find(BinarySearchTree treeUsed, String findThis)
{
//create a new contact with all fields being the same, find is dependent and comparator on tree;
Contact tempContact = new Contact(findThis, findThis, findThis);
return treeUsed.getEntry(tempContact); // where getEntry returns a list of all matching contacts
}
I could do something like
public List<Contact> find(EnumField field, String findThis)
{
BST treeUsed;
switch(Field){
case FIRST:
treeUsed = this.searchTreeFirstName;
break;
cast LAST:
treeUsed = this.searchTreeLastName;
break;
Contact tempContact = new Contact(findThis, findThis, findThis);
return treeUsed.getEntry(tempContact); // where getEntry returns a list of all matching contacts
}
Enum could provide different implementation of its method. A good example would be Math operation:
enum Op {
PLUS {
int exec(int l, int r) { return l + r; }
},
MINUS {
int exec(int l, int r) { return l - r; }
};
abstract int exec(int l, int r);
}
Then I could do Op.PLUS.exec(5, 7) to perform 5 plus 7
See http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html for more detail on how to use enum.
In your case, I wouldn't use enum for something having loads of logic and state, but here is how you could use enum with methods having different implementations.
enum BSTType {
SearchTreeFirstName {
void someMethod(Contact c) {...}
},
SearchTreeLastName {
void someMethod(Contact c) {...}
};
abstract void somemethod(Contact c);
}
public boolean modify(Contact contactToFind, BSTType bstType, String newContactInfo) {
// ...
bstType.someMethod(contact);
// ...
}
By looking at the variable name and class name, I think what you actually meant is indexing Contact in a TreeSet either by first name or last name
enum IndexType implements Comparator<Contact> {
IndexByFirstName {
#Override
public int compare(Contact o1, Contact o2) {
return o1.firstName.compareTo(o2.firstName);
}
},
IndexByLastName {
#Override
public int compare(Contact o1, Contact o2) {
return o1.lastName.compareTo(o2.lastName);
}
};
}
TreeSet<Contact> contacts = new TreeSet<Contact>(IndexType.IndexByLastName);

How to set and get the cell value of JavaFX Table like swing JTable

I am new to JavaFX and would like to know how to set and get the cell value of JavaFX Table like Swing JTable. i.e. an alternative of setValueAt() & getValueAt of Swing JTable in JavaFX Table.
//would like to get the index of column by Name
int index_RunnableQueueItem = tableQueue.getColumns().indexOf("RunnableQueueItem");
//would like to get the selected row
int row = tableQueue.getSelectionModel().getSelectedIndex();
if (index_RunnableQueueItem != -1 && row != -1) {
// would like to get the value at index of row and column.
//Update that value and set back to cell.
}
TableView really doesn't support this methodology.
Here's a somewhat brittle means of doing what you want, using reflection. It's entirely dependent upon you using PropertyValueFactory in your cell value factory so it can lookup the property name, though.
class MyItem
{
SimpleStringProperty nameProperty = new SimpleStringProperty("name");
public MyItem(String name) {
nameProperty.set(name);
}
public String getName() { return nameProperty.get(); }
public void setName(String name) { nameProperty.set(name); }
public SimpleStringProperty getNameProperty() { return nameProperty; }
}
...
TableView<MyItem> t = new TableView<MyItem>();
TableColumn col = new TableColumn("Name Header");
col.setCellValueFactory(new PropertyValueFactory<MyItem, String>("name"));
t.getColumns().addAll(t);
...
public void setValue(int row, int col, Object val)
{
final MyItem selectedRow = t.getItems().get(row);
final TableColumn<MyItem,?> selectedColumn = t.getColumns().get(col);
// Lookup the propery name for this column
final String propertyName = ((PropertyValueFactory)selectedColumn.getCellValueFactory()).getProperty();
try
{
// Use reflection to get the property
final Field f = MyItem.class.getField(propertyName);
final Object o = f.get(selectedRow);
// Modify the value based on the type of property
if (o instanceof SimpleStringProperty)
{
((SimpleStringProperty)o).setValue(val.toString());
}
else if (o instanceof SimpleIntegerProperty)
{
...
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
Retrieving a simple value from a JavaFx TableView Cell
You can use listeners as listed in other posts, but if you wish to get just a simple value from a cell you can use a simpler method
Example:
// Get the row index where your value is stored
int rowIndex = tableView.getSelectionModel().getSelectedIndex();
// Since you can't get the value directly from the table like the
// getValueAt method in JTable, you need to retrieve the entire row in
// FXCollections ObservableList object
ObservableList rowList =
(ObservableList) tableViewModelos.getItems().get(rowIndex);
// Now you have an ObservableList object where you can retrieve any value
// you have stored using the columnIndex you now your value is, starting
// indexes at 0;
// In my case, I want to retrieve the first value corresponding to the first column //index, and I know it is an Integer Value so I'll cast the object.
int columnIndex = 0;
int value = Integer.parseInt(rowList.get(columnIndex).toString());
Hope this expample helps you.

Categories