Question

Ok, so I think my problem here stems from a fundamental lack of understanding as to what a JList is actually doing.

I have a simple example class MyList.

package test;

import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;

public class MyList extends JList<String> {
    public MyList(Vector<String> myStrings){
        super(myStrings);
        this.setCellRenderer(new ListCellRenderer<String>(){
            @Override
            public Component getListCellRendererComponent(
                    JList<? extends String> list, String value, int index,
                    boolean isSelected, boolean cellHasFocus) {
                String myString = value.toString();
                return new JLabel(myString+" (idx "+index+")");
            }

        });

        this.addMouseListener(new MouseAdapter(){
            @Override
            public void mousePressed(MouseEvent e) {
                MyList p = (MyList) e.getSource();
                Component c = p.findComponentAt(e.getX(), e.getY());
                System.out.println("am clicking on "+c.getClass()+" in "+p.getClass());
            }
        });
    }

    public static void main(String[] args){
        Vector<String> myStrings = new Vector<String>();
        myStrings.addAll(Arrays.asList("str 1","str 2","str 3"));
        MyList mine = new MyList(myStrings);
        JFrame myFrame = new JFrame();
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myFrame.setSize(500, 500);
        myFrame.add(mine);
        myFrame.setVisible(true);
    }
}

The output of clicking on any JLabel inside the list is the same:

am clicking on class test.MyList in class test.MyList

I expected it to be:

am clicking on class javax.swing.JLabel in class test.MyList

I think this as something to do with how the ListCellRenderer works, but I am not sure. Why isn't the component I get back from p.findComponentAt(e.getX(), e.getY()); a JLabel? What is going on here?

Was it helpful?

Solution

Why isn't the component I get back from p.findComponentAt(e.getX(), e.getY()); a JLabel? What is going on here?

JLists and JTables put in extra effort to efficiently display a lot of information while minimizing overhead doing so. One way they do this is by displaying information via renderers. What you are seeing in a JList are not true JLabels but images of JLabels (or whatever components are used as the renderer). The JList uses the same renderer to create images for each element in the column. So say you have a JList with 1000 items, rather than create 1000 JLabels, the JList creates just one, uses it to create JLabel images, and then displays the images. So what you are clicking on is truly a JList and not a JLabel.

To test this further, try using a JTextField as a renderer, and you'll quickly find that the cell does not behave like a JTextField and that you can't edit the information that the it displays.

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