Tomas Bisciak Tomas Bisciak - 2 months ago 14
Java Question

JavaFX listview duplication of rendered items when added to observableList

I have a ListView with observableList attached to it,

@FXML
private ListView<Weapon> listViewWeapons;

....
//initialize
listViewWeapons.setCellFactory(lv -> new CustomWeaponDetailListCell<>());
listViewWeapons.setItems(CsgoRr.getModel().getWeaponCache());


Custom cell:

public class CustomWeaponDetailListCell<T extends Weapon> extends ListCell<T> {

private final StringBuilder sb = new StringBuilder();

@Override
public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
} else {
sb.append(item.getName()).append(" Detail:")
.append((String) CsgoRr.objectToJsonString(item.getRecoilPattern()));

setText(sb.toString());
}
}
}


Function for creating new Weapon and adding it to a database and a list:

private static int newWeaponNameIncrement = 1;

@FXML
private void newWeaponOnAction() {
try {
System.out.println("DEBUG WEAPON NAME TRYING TO BE CREATED IS :" + "newWeapon" + newWeaponNameIncrement);
Weapon newWeapon = Weapon.createWeapon("newWeapon" + newWeaponNameIncrement,
new RecoilPattern());
newWeapon.setId(DbUtil.storeWeapon(newWeapon));

CsgoRr.getModel().getWeaponCache().add(newWeapon);
} catch (SQLException ex) {
if (ex.getErrorCode() == 23505) {//duplicate name
System.out.println("DEBUG :Duplicate name on add new weapon");
newWeaponNameIncrement++;
newWeaponOnAction();
}

Logger.getLogger(WeaponViewController.class.getName()).log(Level.SEVERE, null, ex);
} catch (AWTException ex) {
Logger.getLogger(WeaponViewController.class.getName()).log(Level.SEVERE, null, ex);
}
}


Everything works fine , data added to an database , bud problem once again is with how i see listView behave problem is demonstrated here in a GIF:

Gif got a bit too big , you have to click link cant embed it here
http://i.imgur.com/6DFtViw.gifv

As you can see from image problem is that it duplicates items in a list at least visually , so change is refreshed bud not in a proper way , once i change view to something else and then goback which calls constructor and initialize method everything looks as it should , anyone knows what the problem is with this?

Wierd part is i have similiar code in other controller whichpoints to my previous SO question which i fixed no problem and works flawlessly, bud when i do this almost same way i have different results here.JavaFX ListView adding item into observable list doesnt reflect change and its not selectable its a different problem since before i didnt had any update feedback now i have feedback bud not the correct one.

I will be thankfull for any feedback here.

Answer

You reuse the same StringBuilder every time the item is swapped without clearing it. This means the resulting String will be the concatenation of all values for items that were stored in the Cell.

You need to use different StringBuilders every time or clear the StringBuilder:

public class CustomWeaponDetailListCell<T extends Weapon> extends ListCell<T> {

    private final StringBuilder sb = new StringBuilder();

    @Override
    public void updateItem(T item, boolean empty) {
        super.updateItem(item, empty);
        if (empty) {
            setText(null);
        } else {
            sb.append(item.getName()).append("    Detail:")
                    .append((String) CsgoRr.objectToJsonString(item.getRecoilPattern()));

            setText(sb.toString());

            // clear StringBuilder content
            sb.delete(0, sb.length());
        }
    }
}
Comments