6

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?

1

2 Answers 2

5

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/

Sign up to request clarification or add additional context in comments.

4 Comments

Correct, the default renderer displays non-icon objects by invoking toString().
-1 for overriding toString for display reasons. The Swing way of custom visual representation is a custom ListCellRenderer.
@kleopatra makes a valuable point; a link the JList tutorial would improve this answer.
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.
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);
});

7 Comments

The class ListSelectionListener has no method getListCellRendererComponent. Did you mean foo.setCellRenderer(new DefaultListCellRenderer()...?
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.
@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.
@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).
@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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.