Search code examples
javaswingjpaneljlist

Custom Render JPanel in a JList


I'm trying to display Panel in a JList by modifying the render.

I tried an example with JLabel (https://www.codejava.net/java-se/swing/jlist-custom-renderer-example) and it's works perfectly (see picture)

Render JLabel

So I tried to adapt it for JPanel (instead of JLabel) but I got an interesting problem and I really don't know how to solve it. Render JPanel

As you can see, instead of appearing only one time, every country and his associated image are displayed on every line and I can't understand why. (There are 8 lines because there are 8 countries)

Here is the code I made :

CountryRenderer.java

import java.awt.*;
import java.io.IOException; 
import javax.imageio.ImageIO;
import javax.swing.*;

public class CountryRenderer extends JPanel implements ListCellRenderer<Country> {

    @Override
    public Component getListCellRendererComponent(JList<? extends Country> list, Country country, int index,
        boolean isSelected, boolean cellHasFocus) {
          
        String code = country.getCode();
        
        // to load and resize the image 
        Image imgSettings = null;
        try {
            imgSettings = ImageIO.read(getClass().getResource("./images/" + code + "1.png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        imgSettings = imgSettings.getScaledInstance(25, 25, imgSettings.SCALE_SMOOTH); 
         
        // create the button and put the image on it
        JButton buttontest = new JButton() ; 
        buttontest.setIcon(new ImageIcon(imgSettings));
        add(buttontest); 
        
        // create the text (name of the country) 
        JTextField txtest = new JTextField(); 
        txtest.setText(country.getName());
        add(txtest); 
       
        return this;
    }
}

and in case you need the 2 other files to make this run, they are on the link I put above or here :

Country.java

public class Country {
     
    private String name;
    private String code;
 
    public Country(String name, String code) {
        this.name = name;
        this.code = code;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getCode() {
        return code;
    }
 
    public void setCode(String code) {
        this.code = code;
    }
    
    @Override
    public String toString() {
        return name;
    }
} 

And here is the file you can run : JListCustomRendererExample.java

import javax.swing.*;
 
public class JListCustomRendererExample extends JFrame {
 
    public JListCustomRendererExample() {
        Country us = new Country("USA", "1");
        Country in = new Country("India", "2");
        Country vn = new Country("Vietnam", "3");
        Country ca = new Country("Canada", "4");
        Country de = new Country("Denmark", "5");
        Country fr = new Country("France", "6");
        Country gb = new Country("Great Britain", "7");
        Country jp = new Country("Japan", "8");
 
        //create the model and add elements
        DefaultListModel<Country> listModel = new DefaultListModel<>();
        listModel.addElement(us);
        listModel.addElement(in);
        listModel.addElement(vn);
        listModel.addElement(ca);
        listModel.addElement(de);
        listModel.addElement(fr);
        listModel.addElement(gb);
        listModel.addElement(jp);
 
        //create the list
        JList<Country> countryList = new JList<>(listModel);
        add(new JScrollPane(countryList));
 
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("JList Renderer Example");
        this.setSize(200, 200);
        this.setLocationRelativeTo(null);
        this.setVisible(true);
        
        countryList.setCellRenderer(new CountryRenderer());
    }
 
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new JListCustomRendererExample();
            }
        });
    }
}

EDIT

I tried with the answer of @Gilbert le blanc but I still have a problem, I tried to add new element to this label, like a button and I wanted these button to have the same text on it that the name of the country row it's on. Example : on the row USA, I want the button to have "USA" on it.

So I added these 4 lines in the public Component getListCellRendererComponent :

label.setLayout(null);
JButton test = new JButton(country.getName()); 
test.setBounds(10,10,50,50);
label.add(test); 

And I got this :

weird JButton

That's not what was expected and that's kinda the same problem that I had with the first question, do you know why ? And is there a solution ?


Solution

  • Well I managed to solve myself by creating a JPanel with listener so it was like a JList but I can put the object I wanted in it so it even work better.