Question

I have a JList that is supported by a DefaultListModel and has a custom CellRenderer.

The CellRenderer is for adding support for JCheckBox in my JList.

When i try to modify the checked state for an element in the DefaultListModel it does not appear to update my JList. This happens when i try to use any of the three methods to get the element at a certain index: DefaultListModel.elementAt(...), DefaultListModel.get(...) or DefaultListModel.getElementAt(...).

Why is my JList not getting the update?

The section of code below in my JList section that is commented out, will work. But, i do not like having to copy a new object into that position just to change the boolean.


Here is my code, simplified for easy reading and understanding.


JList section

public AppsPanel() {
    super(new BorderLayout());

    this.appsListModel = new DefaultListModel<AppListItem>();
    this.appsList = new JList<AppListItem>(this.appsListModel);
    this.appsList.setCellRenderer(new AppsListRenderer());
    this.appsList.addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            JList list = (JList) e.getSource();
            int index = list.locationToIndex(e.getPoint());

            AppListItem appListItem = (AppListItem)list.getModel().getElementAt(index);
            appListItem.setSelected(!appListItem.isSelected());

            list.repaint(list.getCellBounds(index, index));
        }
    });
    this.appsScrollPane = new JScrollPane(this.appsList);
    this.add(this.appsScrollPane);
}
...
public void selectAllApps() {
//        for (int i = 0; i < this.appsListModel.size(); i++) {
//            this.appsListModel.set(i, new AppListItem(this.appsListModel.get(i).getApp(), true));
//        }
    for (int i = 0; i < this.appsListModel.size(); i++) {
        this.appsListModel.getElementAt(i).setSelected(true);
    }
}

CellRenderer section.

public class AppsListRenderer extends JCheckBox implements ListCellRenderer<AppListItem> {

        @Override
        public Component getListCellRendererComponent(JList<? extends AppListItem> list, AppListItem value, int index, boolean isSelected, boolean cellHasFocus) {
            this.setSelected(value.isSelected());
            if (value.getApp() != null) {
                this.setText(value.getApp().getAppName());
            }
            return this;
        }
    }

AppListItem pojo

public class AppListItem {

    private App app;

    private boolean selected;

    public AppListItem(App app, boolean selected) {
        this.app = app;
        this.selected = selected;
    }

    public App getApp() {
        return app;
    }

    public void setApp(App app) {
        this.app = app;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }
}

App pojo

public class App {

    private String appName;

    private String appPath;

    public App(String appName, String appPath) {
        this.appName = appName;
        this.appPath = appPath;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public String getAppPath() {
        return this.appPath;
    }

    public void setAppPath(String appPath) {
        this.appPath = appPath;
    }
}
Was it helpful?

Solution

Your selectAllApps() does not trigger any event. Since you can’t invoke one of the fire… methods on the default model you should at least invoke repaint on the JList after the update.

But I recommend implementing your own model; it’s not that hard.

public class MyListModel extends AbstractListModel<AppListItem> {

    ArrayList<AppListItem> list=new ArrayList<>();

    public void selectAllApps() {
        for(AppListItem i:list) i.setSelected(true);
        fireContentsChanged(this, 0, getSize()-1);
    }

    public int getSize() {
      return list.size();
    }

    public AppListItem getElementAt(int index) {
      return list.get(index);
    }

    // if you need such updates:
    public void add(int index, AppListItem item) {
      list.add(index, item);
      fireIntervalAdded(this, index, index);
    }

    public boolean remove(AppListItem i) {
      int index = list.indexOf(i);
      if(index<0) return false;
      remove(index);
      return true;
    }

    public void remove(int index) {
      list.remove(index);
      fireIntervalRemoved(this, index, index);
    }
}

OTHER TIPS

Use the following method of AbstractListModel, at the point where you want the change to be applied to JList.

fireContentsChanged (model, changeStartIndex, changeEndIndex);

The changed elements are specified by the closed interval changeStartIndex, changeEndIndex-- the endpoints are included.

Example: http://www.javafaq.nu/java-example-code-674.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top