Search code examples
javaswinglistcellrenderer

Why removeAll() is required in ListCellRenderer?


This is my code:-

public class MyRender extends JPanel implements ListCellRenderer {

    ImageIcon on_img;
    JLabel name = new JLabel();
    JLabel icn = new JLabel();
    JLabel img = new JLabel();

    public MyRender(Atalk) {
        setOpaque(true);
        setBackground(Color.WHITE);
        setForeground(Color.black);
        on_img = new ImageIcon(MyCls.class.getClassLoader().getResource("imgPath"));
    }

    @Override
    public Component getListCellRendererComponent(JList list, Object value,
            int index, boolean isSelected, boolean cellHasFocus) {
        if (value != null) {
            removeAll();
            setLayout(new BorderLayout());
            User user = (User) value;
            String pres = user.getPresence().toLowerCase();
            img.setIcon(default_img);
            if (pres.contains("unavailable"))
                icn.setIcon(off_img);
            else
                icn.setIcon(on_img);
            name.setText(user.getName());
            JPanel panel = new JPanel();
            panel.setLayout(new BorderLayout());

            add(img, BorderLayout.EAST);
            add(icn, BorderLayout.WEST);

            panel.add(st, BorderLayout.CENTER);
            panel.add(name, BorderLayout.NORTH);

            add(panel, BorderLayout.CENTER);

            JLabel lbl = new JLabel(" ");
            lbl.setSize(100, 5);
            add(lbl, BorderLayout.AFTER_LAST_LINE);

            if (isSelected) {
                setBackground(Color.lightGray);
                panel.setBackground(Color.lightGray);
            } else {
                setBackground(Color.white);
                panel.setBackground(Color.white);
            }

            return this;
        }
        return null;
    }
}

As you can see I have called removeAll() method. If I remove that line the data is not displayed properly. All data overlaps each other. And If I add removeAll() all works fine. Why this happens? Is it necessary to call removeAll()?


Solution

  • You have to restructure your class so that all children of MyRender are created and added at construction time.

    getListCellRendererComponent() should be used ONLY to change values or visual attributes (e.g. background) of existing components.

    Don't forget that getListCellRendererComponent() should be as fast as possible (it can be called quite frequently), hence it should not create components but only modify existing ones.

    Typically, here is how your getListCellRendererComponent() method should look like:

    @Override
    public Component getListCellRendererComponent(
        JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        if (value != null) {
            User user = (User) value;
            String pres = user.getPresence().toLowerCase();
            img.setIcon(default_img);
            if (pres.contains("unavailable"))
                icn.setIcon(off_img);
            else
                icn.setIcon(on_img);
            name.setText(user.getName());
            if (isSelected) {
                setBackground(Color.lightGray);
                panel.setBackground(Color.lightGray);
            } else {
                setBackground(Color.white);
                panel.setBackground(Color.white);
            }
        }
        return this;
    }