Update highlighted cell in javafx - java

I use two text fields and a button to add entries to a two column table.
If I add a new entry the table is updated right away:
private void addBtn(ActionEvent event) {
Test o = new Test();
o.setTitle(title.getText());
o.setCount(Integer.parseInt(count.getText()));
mainApp.getData().add(o);
}
In a second step I added an additional button to amend the highlighted count cell:
private void editBtn(ActionEvent event) {
Test o = getSelection();
o.setCount(Integer.parseInt(count.getText()));
mainApp.getData().set(tablePosition, o);
}
If I click the button, the cell will update the value, but it's not visible in the table. If I click the button a second time it will update the table.
To check for which row is highlighted I use the following functions:
private final ListChangeListener<Test> selector = new ListChangeListener<Test>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Test> c) {
setSelection();
}
};
public Test getSelection() {
if (testTable != null) {
List<Test> table = testTable.getSelectionModel().getSelectedItems();
if (table.size() == 1) {
final Test selection = table.get(0);
return selection;
}
}
return null;
}
private void setSelection() {
final Test o = getSelection();
tablePosition = mainApp.getData().indexOf(o);
if (o != null) {
title.setText(o.getTitle());
count.setText(o.getCount().toString());
}
}
In the initialize method I add a listener to the observable list:
final ObservableList<Test> t1 = testTable.getSelectionModel().getSelectedItems();
t1.addListener(selector);
My Test class:
public class Test {
private final SimpleStringProperty title = new SimpleStringProperty();
private final SimpleIntegerProperty count = new SimpleIntegerProperty();
public void setTitle(String title) {
this.title.set(title);
}
public String getTitle() {
return title.get();
}
public void setCount(Integer count) {
this.count.set(count);
}
public Integer getCount() {
return count.get();
}
}
How can I make the Edit button to update the cell value right away?

Assuming you are using a PropertyValueFactory as the cell factory for your table columns, you need to provide property accessor methods in order that the table cell provided by the PropertyValueFactory can listen to those properties for changes.
One correct implementation of using the JavaFX Property model looks like
public class Test {
private final IntegerProperty count = new SimpleIntegerProperty(this, "count", 0);
private final StringProperty title = new SimpleStringProperty(this, "title", "");
public final int getCount() {
return count.get();
}
public final void setCount(int count) {
this.count.set(count);
}
public IntegerProperty countProperty() {
return count ;
}
public final String getTitle() {
return title.get();
}
public final void setTitle(String title) {
this.title.set(title);
}
public StringProperty titleProperty() {
return title ;
}
}
With that, the following method will then correctly update the selected row in the table:
private void editBtn(ActionEvent event) {
Test o = testTable.getSelectionModel().getSelectedItem();
if (o != null) {
o.setCount(Integer.parseInt(count.getText()));
}
}
If that doesn't fix the problem for you, I recommend you edit your question completely and provide a sscce that demonstrates the problem.

Related

Realm does not save attributes, object is not managed although copied to Realm

I have an issue with realm. I receive a custom object from an API. I assign this object to a POJO object using retrofit. Within this object I have an ArrayList of the ToDoItemobject which extends RealmObject.
I receive the data correctly with all attributes, everything gets correctly assigned. I run it through my synchronization algorithm and save it to realm in a writing transaction. But when retrieving the data after realm.commit(); the attributes of the objects are all 0 or null.
The method isManaged()is always false, even after the writing transaction, which I don't understand because in the official documentation is states that a POJO can be converted to a managed object using the copyToRealm method.
I already tried a number of things: creating the GetItemResponseClass as RealmObject, but not possible since it has to extend JSONObject to correctly receive the data from the API. I also tried to write the whole list directly to realm but the result was the same.
As a side note, it can be that my method syncPendingLists has some logic errors, but I couldn't debug it yet, since the attributes were always o and null. Thanks for any help.
Here my code from the Activity:
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
RealmResults<Counter> counterList = realm.where(Counter.class).findAll();
//setting up counterObject
if (counterList.isEmpty()) {
counterObject = new Counter();
COUNTER = counterObject.getCounter();
} else {
counterObject = counterList.get(0);
COUNTER = counterObject.getCounter();
}
initializeLists();
//Adding the Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new DoneListFragment(), "DoneListFragment");
ft.add(R.id.fragment_container, new PendingListFragment(), "PendingListFragment");
ft.commit();
RetrofitClient retrofitClient = new RetrofitClient();
Retrofit retrofit = retrofitClient.getClient();
mAPIInterface = retrofit.create(ToDoistAPIInterface.class);
}
public void getRemoteItems() {
final ArrayList<ToDoItem> onlineItems = new ArrayList<ToDoItem>();
JSONArray array = new JSONArray();
array.put("items");
String auxMessage = array.toString();
mAPIInterface.getItems(RetrofitClient.TOKEN, "*", auxMessage).enqueue(new Callback<GetItemsResponseClass>() {
#Override
public void onResponse(Call<GetItemsResponseClass> call, Response<GetItemsResponseClass> response) {
GetItemsResponseClass itemsResponseClass = new GetItemsResponseClass();
itemsResponseClass = response.body();
remoteItemsList = itemsResponseClass.getItems();
boolean test = remoteItemsList.get(0).isManaged(); //returns false
boolean test1 = remoteItemsList.get(0).isValid(); //returns true refers to singleton RealmObject
syncPendingLists(pendingItemList, remoteItemsList);
}
#Override
public void onFailure(Call<GetItemsResponseClass> call, Throwable t) {
Snackbar.make(floatingButton, "Ups - Couldn't sync items, next time, I promise", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initializeLists() {
RealmResults<ToDoItem> realmToDoItemPendingList = realm.where(ToDoItem.class).equalTo("checkedOffline", false).findAll();
initializingArrayListFromDB(realmToDoItemPendingList, pendingItemList);
RealmResults<ToDoItem> realmToDoItemDoneList = realm.where(ToDoItem.class).equalTo("checkedOffline", true).findAll();
initializingArrayListFromDB(realmToDoItemDoneList, doneItemList);
}
private void initializingArrayListFromDB(RealmResults<ToDoItem> realmToDoItemPendingList, ArrayList<ToDoItem> arrayList) {
int h;
for (h = 0; h < realmToDoItemPendingList.size(); h++) {
arrayList.add(realmToDoItemPendingList.get(h));
}
}
public void syncPendingLists(ArrayList<ToDoItem> offlinePendingList, ArrayList<ToDoItem> onlinePendingList) {
//is my sync algorithm, the important part is the for loop at the end of this method
boolean hasMatch = false;
boolean itemChanged = false;
Date offlineDate = null;
Date onlineDate = null;
if (!offlinePendingList.isEmpty()) {
for (ToDoItem item1 : offlinePendingList) {
if (item1.getId() < 10000) {
try {
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
for (int i = 0; i < onlinePendingList.size(); i++) {
if (item1.getId() == onlinePendingList.get(i).getId()) {
hasMatch = true;
onlinePendingList.remove(onlinePendingList.get(i));
//Compare Fields
if (!item1.getContent().equals(onlinePendingList.get(i).getContent())) {
itemChanged = true;
}
if (item1.getPriority() != onlinePendingList.get(i).getPriority()) {
itemChanged = true;
}
if (!item1.getDate_string().equals(onlinePendingList.get(i).getDate_string())) {
itemChanged = true;
}
if (itemChanged == true) {
//Format edit dates to date
DateFormat format = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
try {
offlineDate = format.parse(item1.getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
try {
onlineDate = format.parse(onlinePendingList.get(i).getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
//compare dates to see which was last edited
if (offlineDate.compareTo(onlineDate) > 0) {
try {
deleteRemoteItem(onlinePendingList.get(i), "item_delete");
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (offlineDate.compareTo(onlineDate) < 0) {
addOrUpdateToDB(item1);
}
}
}
if (!hasMatch) {
deleteObjectFromDB(item1);
}
}
}
}
}
for (ToDoItem onlineItem1 : onlinePendingList) {
boolean isManaged1 = onlineItem1.isManaged(); //returns false, which is ok since it is not yet in the realm db
onlineItem1.setLocalId(counterObject.getCounter());
addOrUpdateToDB(onlineItem1);
boolean asdf = onlineItem1.isManaged(); //it returns false, but it should return true
incrementCounter(counterObject);
}
initializeLists();
getPendingListFragment().refreshFragment();
}
private void addOrUpdateToDB(ToDoItem newItem) {
boolean test2= newItem.isManaged(); //returns false
realm.beginTransaction();
realm.copyToRealmOrUpdate(newItem);
//realm.copyToRealm(newItem); //I tried this method as well, but no difference
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and here is the problem, it should return true, shouldn't it?
assignValuesToToDoItem(itemWithValues, newItem);
saveCounterToDB(counterObject);
}
}
Here my class code of ToDoItem:
public class ToDoItem extends RealmObject implements Parcelable {
public static final Creator<ToDoItem> CREATOR = new Creator<ToDoItem>() {
#Override
public ToDoItem createFromParcel(Parcel in) {
return new ToDoItem(in);
}
#Override
public ToDoItem[] newArray(int size) {
return new ToDoItem[size];
}
};
#PrimaryKey
private long localId;
private String content;
private boolean checkedOffline = false;
private int priority;
private String date_string;
private String temp_id;
private long id;
private String date_added;
public ToDoItem(String name) {
this.content = name;
}
public ToDoItem() {
}
protected ToDoItem(Parcel in) {
localId = in.readLong();
content = in.readString();
checkedOffline = in.readByte() != 0;
priority = in.readInt();
date_string = in.readString();
temp_id = in.readString();
id = in.readLong();
date_added=in.readString();
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isCheckedOffline() {
return checkedOffline;
}
public void setCheckedOffline(boolean checkedOffline) {
this.checkedOffline = checkedOffline;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setRemote_id(Long remote_id) {
this.id = remote_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isDone() {
return checkedOffline;
}
public String getDate_string() {
return date_string;
}
public void setDate_string(String date_string) {
this.date_string = date_string;
}
public long getLocalId() {
return this.localId;
}
public void setLocalId(long i) {
this.localId = i;
}
public String getTemp_id() {
return temp_id;
}
public void setTemp_id(String temp_id) {
this.temp_id = temp_id;
}
public String getDateAdded() {
return date_added;
}
public void setDateAdded(String dateAdded) {
this.date_added = dateAdded;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(localId);
dest.writeString(content);
dest.writeByte((byte) (checkedOffline ? 1 : 0));
dest.writeInt((priority));
dest.writeString(date_string);
dest.writeString(temp_id);
dest.writeLong(id);
dest.writeString(date_added);
}
#Override
public String toString() {
return "localId: " + localId + "; content: " + content;
}
}
And here the code for the GetItemsResponseClass:
public class GetItemsResponseClass extends JSONObject {
private String sync_token;
#SerializedName("temp_id_mapping")
private HashMap<String, Long> temp_id_mapping;
private boolean full_sync;
#SerializedName("items")
private ArrayList<ToDoItem> items;
public GetItemsResponseClass(){
}
public String getSync_token() {
return sync_token;
}
public void setSync_token(String sync_token) {
this.sync_token = sync_token;
}
public HashMap<String, Long> getTemp_id_mapping() {
return temp_id_mapping;
}
public void setTemp_id_mapping(HashMap<String, Long> temp_id_mapping) {
this.temp_id_mapping = temp_id_mapping;
}
public boolean isFull_sync() {
return full_sync;
}
public void setFull_sync(boolean full_sync) {
this.full_sync = full_sync;
}
public ArrayList<ToDoItem> getItems() {
return items;
}
public void setItems(ArrayList<ToDoItem> items) {
this.items = items;
}
}
EDIT: Apparently it is a desired behavior that the object does not get saved with its attributes. Consequently to assign the values you have to use getters and setters. I added the following method, however even when debugging with a watch, as stated in the official documentation the values do not get assigned:
private void assignValuesToToDoItem(ToDoItem itemWithValues, ToDoItem newItem) {
realm.beginTransaction();
newItem.setContent(itemWithValues.getContent()); //the content variable stays null
newItem.setCheckedOffline(itemWithValues.isDone()); //stays false
newItem.setPriority(itemWithValues.getPriority());
newItem.setDate_string(itemWithValues.getDate_string());
newItem.setTemp_id(itemWithValues.getTemp_id());
newItem.setId(itemWithValues.getId());
newItem.setDate_added(itemWithValues.getDate_added());
realm.commitTransaction();
}
I added this line assignValuesToToDoItem(itemWithValues, newItem); in the main activity in the method private void addOrUpdateToDB(ToDoItem newItem) {...}
Same result...
I found out 2 very important things:
The attributes are saved, however in the debugging window they appear to be 0, false or null
Even putting a Debugging Watch does not show the correct values.
To see the real value how it is in the database you have to add a Watch and put the watch directly on the getters of the object. In my case I added a Watch and typed in "newItem.getContent()". With this line I got the title of my object. However just putting a Watch with "newItem" shows "null".
copyToRealm() and copyToRealmOrUpdate() returns the managed proxy as a return value of the function you're calling.
realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and it should return false
Should be
newItem = realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns true

JavaFX TableView not updating immediately

I have an issue with JavaFX TableView UI update. After I change the observable object, it does not update the UI of TableView. But if I perform a magical ritual of pulling TableView's scroll bar down and up again - it seems to redraw the table and update items in it.
Through debugging I've ensured, that the PreferencesSet ArrayList and object are updated correctly.
Here's gif demonstration of what is happening
This is my first time asking a question here, so I could have left out some important info. Feel free to ask me for it. Thank you in advance.
Here's code (I have left out unrelated stuff):
ControllerClass:
public class TestSomethingController implements Initializable {
public TableView<PreferenceValues.PreferencesSet> preferencesTable;
public TableColumn mdColumn;
public TableColumn typeColumn;
public TableColumn tradeColumn;
public TableColumn plastColumn;
public TableColumn capColumn;
public TableColumn multColumn;
public TableColumn sizeColumn;
#Override
public void initialize(URL location, ResourceBundle resources) {
setNorthPanel();
setTableColumns();
fillAllInfo();
}
private void setTableColumns() {
mdColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, MarketDirection>("md"));
typeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, UserOfferType>("type"));
tradeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Boolean>("trade"));
plastColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Long>("plast"));
capColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Double>("cap"));
multColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Double>("mult"));
sizeColumn.setCellValueFactory(new PropertyValueFactory<PreferenceValues.PreferencesSet, Long>("size"));
}
private void fillAllInfo() {
preferencesTable.setItems(FXCollections.observableArrayList(CurrentSession.currentUser.getPreferencesList()));
fillNorthPanel();
}
public void applyClicked(ActionEvent actionEvent) {
applyNorthPanelChanges();
}
private void applyNorthPanelChanges() {
PreferenceValues.PreferencesSet preferencesSet = CurrentSession.currentUser.getPreferencesSet(dirChoiceBox.getSelectionModel().getSelectedItem(), offerTypeChoiceBox.getSelectionModel().getSelectedItem());
preferencesSet.setTrade(tradeCheckBox.isSelected());
preferencesSet.setPlast(plastSpinner.getValue());
preferencesSet.setCap(capRateSpinner.getValue());
preferencesSet.setMult(multSpinner.getValue());
preferencesSet.setSize(sizeSpinner.getValue());
preferencesSet.savePreferences();
}
User class:
public class User {
private PreferenceValues preferenceValues;
public PreferenceValues.PreferencesSet getPreferencesSet(MarketDirection md, UserOfferType userOfferType) {
return preferenceValues.getPreferencesSet(md, userOfferType);
}
public ArrayList<PreferenceValues.PreferencesSet> getPreferencesList() {
return preferenceValues.getPreferencesList();
}
}
PreferenceValues class:
import java.util.ArrayList;
import java.util.TreeMap;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
public class PreferenceValues {
private Preferences preferences;
private ArrayList<PreferencesSet> preferencesList;
private TreeMap<String, PreferencesSet> preferencesMap;
public PreferenceValues(User user) {
preferencesList = new ArrayList<>();
preferencesMap = new TreeMap<>();
preferences = Preferences.userRoot().node("prefexample" + user.getwmId());
for (MarketDirection md : MarketDirection.values()) {
for (UserOfferType userOfferType : UserOfferType.values()) {
if (userOfferType != UserOfferType.UNDEF) {
PreferencesSet preferencesSet = new PreferencesSet(md, userOfferType, preferences);
preferencesList.add(preferencesSet);
preferencesMap.put(md.toString() + userOfferType.toString(), preferencesSet);
}
}
}
}
protected ArrayList<PreferencesSet> getPreferencesList() {
return preferencesList;
}
private String getMapKey(MarketDirection md, UserOfferType userOfferType) {
return md.toString() + userOfferType.toString();
}
protected PreferencesSet getPreferencesSet(MarketDirection md, UserOfferType userOfferType) {
return preferencesMap.get(getMapKey(md, userOfferType));
}
public void clear() throws BackingStoreException {
preferences.clear();
}
public class PreferencesSet {
Preferences preferences;
private MarketDirection md;
private UserOfferType type;
private boolean trade;
private int plast;
private double cap;
private double mult;
private int size;
public PreferencesSet(MarketDirection md, UserOfferType type, Preferences preferences) {
this.md = md;
this.type = type;
this.preferences = preferences;
trade = preferences.node(md.toString()).node(type.toString()).getBoolean("trade", false);
plast = preferences.node(md.toString()).node(type.toString()).getInt("plast", 222);
cap = preferences.node(md.toString()).node(type.toString()).getDouble("cap", 333);
mult = preferences.node(md.toString()).node(type.toString()).getDouble("mult", 1);
size = preferences.node(md.toString()).node(type.toString()).getInt("size", 15000);
}
public void savePreferences() {
preferences.node(md.toString()).node(type.toString()).putBoolean("trade", trade);
preferences.node(md.toString()).node(type.toString()).putInt("plast", plast);
preferences.node(md.toString()).node(type.toString()).putDouble("cap", cap);
preferences.node(md.toString()).node(type.toString()).putDouble("mult", mult);
preferences.node(md.toString()).node(type.toString()).putInt("size", size);
}
public MarketDirection getMd() {
return md;
}
public UserOfferType getType() {
return type;
}
public boolean isTrade() {
return trade;
}
public int getPlast() {
return plast;
}
public double getCap() {
return cap;
}
public double getMult() {
return mult;
}
public int getSize() {
return size;
}
public void setTrade(boolean trade) {
this.trade = trade;
}
public void setPlast(int plast) {
this.plast = plast;
}
public void setCap(double cap) {
this.cap = cap;
}
public void setMult(double mult) {
this.mult = mult;
}
public void setSize(int size) {
this.size = size;
}
}
}
Since the only way for PropertyValueFactory to retrieve the value is using the getter, changes of a property cannot be observed and therefore the update only happens, when the item is associated with a new TableRow.
Starting with JavaFX 8u60 you can simply call the refresh method of TableView, which will force an update to be executed.
However the usual way of doing this is by providing access to a property object containing the property value, e.g.
In PreferencesSet
private final IntegerProperty plast = new SimpleIntegerProperty();
public void setPlast(int plast) {
this.plast.set(plast);
}
public int getPlast() {
return plast.get();
}
// this method will be used by the PropertyValueFactory
// and returns a Property which notifies TableView of changes
public IntegerProperty plastProperty() {
return plast;
}
There are other property types for the other data types, see javafx.beans.property package

Vaadin TwinColSelect filter only one column

I have a TwinColSelect and a Textfield that I use to filter the content of the table, it works great, but the problem is that the filter filters the content of both columnos of the TwinColSelect, and I would like to know if it is possible that it only affects to the left column.
My code right now looks like this:
final TwinColSelect select = new TwinColSelect();
select.setItemCaptionPropertyId(PersistenceLoinc.CORPUS_NOMBRE);
TextField filtro = new TextField();
filtro.addTextChangeListener(new TextChangeListener() {
private static final long serialVersionUID = 1L;
SimpleStringFilter filter = null;
#Override
public void textChange(TextChangeEvent event) {
Filterable f = (Filterable) select.getContainerDataSource();
if (filter != null) {
f.removeContainerFilter(filter);
}
filter = new SimpleStringFilter(select.getItemCaptionPropertyId(), event.getText(), true, false);
f.addContainerFilter(filter);
}
});
Thanks,
Cris.
I followed the suggestion from #andreSchild in the comments section of the question, and developed the following class that works perfectly:
public class TwinColSelectStringFilter implements Container.Filter {
final SimpleStringFilter spf;
final TwinColSelect select;
final Object propertyId;
public TwinColSelectStringFilter(Object propertyId, String filterString, boolean ignoreCase, boolean onlyMatchPrefix, TwinColSelect select) {
spf = new SimpleStringFilter(propertyId, filterString, ignoreCase, onlyMatchPrefix);
this.select = select;
this.propertyId=propertyId;
}
#Override
public boolean passesFilter(Object itemId, Item item) throws UnsupportedOperationException {
if(select.getValue() != null && (select.getValue() instanceof Collection)) {
if (((Collection<Integer>) select.getValue()).contains(itemId)) {
return true;
}
}
return spf.passesFilter(itemId, item);
}
#Override
public boolean appliesToProperty(Object propertyId) {
return spf.appliesToProperty(propertyId);
}
}

Inserting Hyperlink in JavaFx TableView

I am trying to insert HyperLink with text "Remove" in all rows of a column. Only TabelView row will be inserted when clicked on a button. The hyperlink also get inserted but not for all rows. It automatically get blank cell for previous row if next row data is added. Screenshot:
The hyperlink listener will be created to remove selected row if clicked on it.
This method is called when user click on a button, here i am creating the link:
public void SalesAdd(ActionEvent actionEvent){
if(quantity.getText().isEmpty()){
quantity.setStyle("-fx-border-color: red");
return;
}
String name = comboBox.getSelectionModel().getSelectedItem();
String batch = batchno.getText();
String exp = expDate.getText();
int qty = Integer.parseInt(quantity.getText());
Double mrp1 = Double.valueOf(mrp.getText());
Double amt = Double.valueOf(amount.getText());
Double mrpAmount = mrp1*qty;
PropertyValueFactory<TableData,String> namePro = new PropertyValueFactory<TableData,String>("name");
PropertyValueFactory<TableData,Integer> qtyPro = new PropertyValueFactory<TableData,Integer>("qty");
PropertyValueFactory<TableData,String> expPro = new PropertyValueFactory<TableData,String>("exp");
PropertyValueFactory<TableData,String> batchPro = new PropertyValueFactory<TableData,String>("batch");
PropertyValueFactory<TableData,Double> mrpPro = new PropertyValueFactory<TableData,Double>("mrp");
PropertyValueFactory<TableData,Double> amtPro = new PropertyValueFactory<TableData,Double>("amt");
PropertyValueFactory<TableData,Hyperlink> rmbutton = new PropertyValueFactory<TableData,Hyperlink>("rbutton");
nameColumn.setCellValueFactory(namePro);
qtyColumn.setCellValueFactory(qtyPro);
expColumn.setCellValueFactory(expPro);
batchColumn.setCellValueFactory(batchPro);
mrpColumn.setCellValueFactory(mrpPro);
amtColumn.setCellValueFactory(amtPro);
removeRowColumn.setCellValueFactory(rmbutton);
for(TableData data:tableData){
if(data.getName()==comboBox.getEditor().getText() || data.getName() == comboBox.getSelectionModel().getSelectedItem().toString()){
common.dialogAlert("Already in Table!","Already in the Table!","Already Exist,Please change the quantity!");
return;
}
}
tableData.add(new TableData(name,batch,exp,qty,mrp1,mrpAmount, rbutton));
tableView.setItems(tableData);
clearInput();
calctotal();
}
The TableData Class:
public class TableData extends ActionEvent {
private final SimpleStringProperty name;
private final SimpleStringProperty batch;
private final SimpleStringProperty exp;
private final SimpleIntegerProperty qty;
private final SimpleDoubleProperty mrp;
private final SimpleDoubleProperty amt;
private final Hyperlink rbutton;
public Hyperlink getRbutton() {
return rbutton;
}
public TableData(String name, String batch,
String exp, int qty, Double mrp, Double amt, Hyperlink rbutton) {
this.name = new SimpleStringProperty(name);
this.batch = new SimpleStringProperty(batch);
this.exp = new SimpleStringProperty(exp);
this.qty = new SimpleIntegerProperty(qty);
this.mrp = new SimpleDoubleProperty(mrp);
this.amt = new SimpleDoubleProperty(amt);
this.rbutton = rbutton;
this.amt.bind(this.qty.multiply(this.mrp));
}
public String getName() {
return name.get();
}
public SimpleStringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public String getBatch() {
return batch.get();
}
public SimpleStringProperty batchProperty() {
return batch;
}
public void setBatch(String batch) {
this.batch.set(batch);
}
public String getExp() {
return exp.get();
}
public SimpleStringProperty expProperty() {
return exp;
}
public void setExp(String exp) {
this.exp.set(exp);
}
public int getQty() {
return qty.get();
}
public SimpleIntegerProperty qtyProperty() {
return qty;
}
public void setQty(int qty) {
this.qty.set(qty);
}
public double getMrp() {
return mrp.get();
}
public SimpleDoubleProperty mrpProperty() {
return mrp;
}
public void setMrp(double mrp) {
this.mrp.set(mrp);
}
public double getAmt() {
return amt.get();
}
public SimpleDoubleProperty amtProperty() {
return amt;
}
public void setAmt(double amt) {
this.amt.set(amt);
}
}
How do i add this same HyperLink for every row in a column?
Including UI elements in the item class is seldom a good idea (also extending ActionEvent seems unnecessary). The link works independent form any item value, therefore it should't use one. Instead use a cell that displays a link when it's non-empty:
public class RemoveCell<T> extends TableCell<T, Void> {
private final Hyperlink link;
public RemoveCell() {
link = new Hyperlink("Remove");
link.setOnAction(evt -> {
// remove row item from tableview
getTableView().getItems().remove(getTableRow().getIndex());
});
}
#Override
protected void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
setGraphic(empty ? null : link);
}
}
This cell does not take any data. Instead the link is displayed only for non-empty cells (setGraphic(empty ? null : link);). When the onAction event of the Hyperlink is triggered, the data available from the TableCell is used to remove the corresponding element from the TableView that contains the cell. Additional code could be added to the body of the lambda expression in case additional operations need to be done on the removal of a item.
Do not use a cellValueFactory for the removeRowColumn (choosing Void as value type only allows for null values), instead just use a cellFactory creating RemoveCells:
removeRowColumn.setCellFactory(tc -> new RemoveCell<>());
BTW: You seem to be recreating the cellValueFactorys on a button click inserting a single new item. It would be a better idea to do this just once for the whole table instead of once per inserted table row.

sorting a datagrid with GWT

I have a datagrid in GWT, and I'm using RPC to populate it with data, I can get the data to show up just fine, and I can also select individual cells but when it comes to sorting it just doesn't work! I can occasionaly click on column headers (it happens intermittently and I'm not sure why) but when I do nothing sorts. I'm using a dataProvider, but I think I'm implementing it incorrectly, I've attached the related code, can someone give me a pointer on how to do this correctly?
first is the actual table itself
public class GuiInventory {
public final static LayoutPanel hpMain = new LayoutPanel();
static ListHandler<OpInventory> sortHandler;
/*
* Define a key provider for a Contact. We use the unique ID as the key,
* which allows to maintain selection even if the name changes.
*/
static ProvidesKey<OpInventory> keyProvider = new ProvidesKey<OpInventory>() {
#Override
public Object getKey(OpInventory item) {
// Always do a null check.
return (item == null) ? null : item.getPartID();
}
};
//the table
final static DataGrid<OpInventory> table = new DataGrid<OpInventory>(keyProvider);
final static SelectionModel<OpInventory> selectionModel = new MultiSelectionModel<OpInventory>(keyProvider);
/**
* The provider that holds the list of contacts in the database.
*/
private final static ListDataProvider<OpInventory> dataProvider = new ListDataProvider<OpInventory>();
public ListDataProvider<OpInventory> getDataProvider() {
return dataProvider;
}
/**
* Add a display to the database. The current range of interest of the display
* will be populated with data.
*
* #param display a {#Link HasData}.
*/
public void addDataDisplay(HasData<OpInventory> display) {
dataProvider.addDataDisplay(display);
}
/**
* Refresh all displays.
*/
public void refreshDisplays() {
dataProvider.refresh();
}
public static Widget init() {
hpMain.clear();
table.setWidth("100%");
table.setSelectionModel(selectionModel);
Ioma.dataservice.getPartInventory(new AsyncCallback<ArrayList<OpInventory>>() {
#Override
public void onFailure(Throwable caught) {
// TODO Auto-generated method stub
}
#Override
public void onSuccess(ArrayList<OpInventory> result) {
dataProvider.setList(result);
// Attach a column sort handler to the ListDataProvider to sort the list.
sortHandler = new ListHandler<OpInventory>(result);
table.addColumnSortHandler(sortHandler);
dataProvider.addDataDisplay(table);
if (table.getColumnCount() == 0) {
initTable();
}
}
});
//add in table
hpMain.add(table);
return hpMain;
}
public static void initTable() {
// Add a text column to show the part ID.
Column<OpInventory, Number> partIDColumn = new Column<OpInventory, Number>(new NumberCell()) {
#Override
public Integer getValue(OpInventory object) {
return object.getPartID();
}
};
table.addColumn(partIDColumn, "Part ID");
table.setColumnWidth(partIDColumn, 4, Unit.PX);
//add a sort to partID
partIDColumn.setSortable(true);
sortHandler.setComparator(partIDColumn, new Comparator<OpInventory>() {
#Override
public int compare(OpInventory o1, OpInventory o2) {
return Integer.valueOf(o1.getPartID()).compareTo(o2.getPartID());
}
});
// Add a text column to show the part Number.
Column<OpInventory, String> partNumberColumn = new Column<OpInventory, String>(new EditTextCell()) {
#Override
public String getValue(OpInventory object) {
return object.getPartNumber();
}
};
table.addColumn(partNumberColumn, "Part Number");
table.setColumnWidth(partNumberColumn, 4, Unit.PX);
//add a sort to the part Number
partNumberColumn.setSortable(true);
sortHandler.setComparator(partNumberColumn, new Comparator<OpInventory>() {
#Override
public int compare(OpInventory o1, OpInventory o2) {
return o1.getPartNumber().compareTo(o2.getPartNumber());
}
});
//add a field updater to be notified when the user enters a new Part Number
partNumberColumn.setFieldUpdater(new FieldUpdater<OpInventory, String>() {
#Override
public void update(int index, OpInventory object, String value) {
object.setPartNumber(value);
//TODO add async call to database to update part Number
table.redraw();
}
});
// Add a text column to show the name.
Column<OpInventory, String> nameColumn = new Column<OpInventory, String>(new EditTextCell()) {
#Override
public String getValue(OpInventory object) {
return object.getName();
}
};
table.addColumn(nameColumn, "Name");
table.setColumnWidth(nameColumn, 10, Unit.PX);
//add a field updater to be notified when the user enters a new part name
nameColumn.setFieldUpdater(new FieldUpdater<OpInventory, String>() {
#Override
public void update(int index, OpInventory object, String value) {
object.setName(value);
//TODO add async call to database to update part name
table.redraw();
}
});
//add a sort to the name
nameColumn.setSortable(true);
sortHandler.setComparator(nameColumn, new Comparator<OpInventory>() {
#Override
public int compare(OpInventory o1, OpInventory o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
this is the Opinventory class to hold each object in the datagrid
public class OpInventory implements Comparable<OpInventory>, IsSerializable {
int partID;
String partNumber;
String name;
String desc;
String partLotNumber;
String supplier;
String reOrderNumber;
boolean isActive;
int quantity;
Double price;
/**
* The key provider that provides the unique ID of a contact.
*/
public static final ProvidesKey<OpInventory> KEY_PROVIDER = new ProvidesKey<OpInventory>() {
#Override
public Object getKey(OpInventory item) {
return item == null ? null : item.getPartID();
}
};
#Override
public int compareTo(OpInventory o) {
return (o == null || o.partNumber == null) ? -1 : -o.partNumber.compareTo(partNumber);
}
#Override
public boolean equals(Object o) {
if (o instanceof OpInventory) {
return partID == ((OpInventory) o).partID;
}
return false;
}
#Override
public int hashCode() {
return partID;
}
public OpInventory(int partID, String partNumber, String name, String desc, String partLotNumber, String supplier, String reOrderNumber, Double price, boolean isActive) {
this.partID = partID;
this.partNumber = partNumber;
this.name = name;
this.desc = desc;
this.partLotNumber = partLotNumber;
this.supplier = supplier;
this.reOrderNumber = reOrderNumber;
this.price = price;
this.isActive = isActive;
}
public OpInventory() {
}
//getters and setters here
}
Apparently my issue was with the fact that I had a keyProvider in both classes, instead of just one. I removed it from the OpInventory class and it seems to work now. this looks like a very specific issue so I expect this question will be closed soon. but I'll leave the code there for future analysis.

Categories

Resources