Adding objects to a JList

11,866

Solution 1

A JList takes in one of its constructor an Object[]. You can get this from your ArrayList with the .toArray() function. I believe (I could be wrong...) that if your User class overrides the toString() method, the JList will use this when it displays your object.

public class User
{
    int id;
    String name;
    String location;

    public String toString() {
      return name;
    }
}

I would recommend reading the documentation for JList in the java docs. It has an example of how to build a custom cell renderer to display items in your list the way you want them displayed. It's pretty easy to follow. It also has an example of how to create the mouse click listener. You should be able to copy/paste this for the most part.

http://docs.oracle.com/javase/6/docs/api/

Solution 2

The JList constructor that we care about for this case takes an array of Objects, as Tony already pointed out. That's about where his answer stops being useful (no offense Tony).

By default, the ListCellRenderer that the JList uses adds JLabels that contain the text from Object#toString(). So, instead of passing Strings, you want to pass it an array of your User Objects, then add a ListSelectionListener (which is used after a user clicks on the JList) and a ListCellRenderer (which determines how a User object is translated into a JComponent that will be drawn as part of the JList).

You want to do something like this (see inline comments for details):

//generate your user data
User[] userData = ...;

//add an array of Objects to a JList using the constructor
//(all classes extend java.lang.Object, including User)
JList foo = new JList(userData);

//overwrite the ListCellRenderer. This will take care of just displaying
//the name of the user
foo.setCellRenderer(new DefaultListCellRenderer(){
    JLabel rv = new JLabel();
    @Override
    public Component getListCellRendererComponent(JList list,
            Object value, int index, boolean isSelected,
            boolean cellHasFocus){
        String s = (value != null && value instanceof User)? ((User)value).name:"";
        rv.setText(s);
        if (isSelected) {
            rv.setBackground(list.getSelectionBackground());
            rv.setForeground(list.getSelectionForeground());
        } else {
            rv.setBackground(list.getBackground());
            rv.setForeground(list.getForeground());
        }
        rv.setEnabled(list.isEnabled());
        rv.setFont(list.getFont());
        rv.setOpaque(true);
        return rv;
    }
});

//Now overwrite the ListSelectionListener which will take care of getting
//user object when the user clicks it
foo.addListSelectionListener(new ListSelectionListener(){
    @Override
    public void valueChanged(ListSelectionEvent lse) {
        User selectedValue = (User)((JList)lse.getSource()).getSelectedValue();
        //now you can do something with the User Object that was just selected
        updateDatabase(selectedValue.id, selectedValue.name,
                selectedValue.location);
});
Share:
11,866
Jim_CS
Author by

Jim_CS

Updated on June 25, 2022

Comments

  • Jim_CS
    Jim_CS almost 2 years

    I have an object - ArrayList<User> users that contains a few user objects.

    public class User
    {
        int id;
        String name;
        String location;
    }
    

    I want to put this ArrayList in a JList so it will display the users names -

    John
    Mick
    Sam
    Joe
    

    --- And when I select a user name an event is fired that lets me perform some action using the appropriate User object. So someone clicks 'Mick' and I get code like this (pseudocode) -

    public jListClicked(User user)
    {
        int id = user.id;
        String name = user.name;
        String location = user.location;
    
        updateDatabase(id, name, location);
    }
    

    I presume this is possible using a JList?? After all I imagine that is what the JList component was created for. So how do I add an object like ArrayList to a JList so I will have the above functionality?

  • trashgod
    trashgod about 12 years
    Correct, the default renderer displays non-icon objects by invoking toString().
  • kleopatra
    kleopatra about 12 years
    -1 for overriding toString for display reasons. The Swing way of custom visual representation is a custom ListCellRenderer.
  • trashgod
    trashgod about 12 years
    @kleopatra makes a valuable point; a link the JList tutorial would improve this answer.
  • searchengine27
    searchengine27 almost 9 years
    I posted an answer to this question which addresses how to solve the OP's concerns properly. I couldn't believe it has been 3+ years and nobody posted an answer yet, so I was compelled to do it lol.
  • chris
    chris over 4 years
    The class ListSelectionListener has no method getListCellRendererComponent. Did you mean foo.setCellRenderer(new DefaultListCellRenderer()...?
  • Marco13
    Marco13 over 4 years
    The DefaultListCellRenderer already is a JLabel. Instead of using the label rv, you should do 1. call super.getListCellRendererComponent(...), 2. afterwards, only do the this.setText(s) call with the String s that you created, 3. then end with return this. The main point is: The super call will take care of the nitty-gritty background/foreground/font/... stuff that you're doing there manually right now.
  • searchengine27
    searchengine27 over 3 years
    @Marco13 1. No. Don't ever do that unless you explicitly want to. This is a contrived example, but the idea is that you likely don't want to call super at all and do any of the logic or waste any of the CPU cycles that the parent implementation does. And why would you do that? Just so you can get a JComponent to return? No, only call super if you really intend to. Again, this is a contrived example to try and demonstrate so it's easy to say just call super here, but 9 times out of 10 when I'm rendering a JTable/JList, I never want super called.
  • Marco13
    Marco13 over 3 years
    @searchengine27 Look at what the super implementation does, and what you had to fiddle with the isSelected flag and the enabled/font stuff, while still ignoring the cellHasFocus value (hint: that's exactly what the super implementation is doing, and it is doing it properly). The "cpu cycles" argument is non-sensical here. Have a look at all the methods like invalidate, repaint etc that are overridden to increase the performence (you didn't do that in your implementation).
  • searchengine27
    searchengine27 over 3 years
    @Marco13 Again, the example I gave was CONTRIVED. You're totally missing the point. In a real world scenario, I would almost never call super because I would almost never just be using a JLabel the way the super is. Take a minute to try and understand what I'm trying to convey instead of just jumping right to the example as a verbatim. It's a contrived example - it's not supposed to be a copy and paste into your production code. In a contrived example, things tend to lose meaning as they would be in production code. I would never (have never) implemented this function this way.
  • Marco13
    Marco13 over 3 years
    With the super-way of doing it, the code could be shorter, easier to read, extend, and maintain, more correct (!), and the result could be more efficient. It could basically be "production code", and I don't think that I have to argue about that (but you should know that people will copy+paste this...).
  • searchengine27
    searchengine27 over 3 years
    I don't care if people copy and paste this. It's not meant to be. If you're coming onto SO to copy and paste things directly from answers, then you're already lost and it's not my problem. This is here for demonstrative purposes and if somebody doesn't get that then I'm not here for them anyway. You should be able to read the answer and understand what the intent is. I'm not going to just put super in an answer for that type of person, and leave out some other details for people who really want to see what's going on.