0
votes

Right now I use DefaultListModel with the wanted list of strings and I display it, via JList, in a JScrollPane.

What I want is to find a specific word in this sentence and to put an imageIcon instead of this word which I will display in the said JScrollPane.

For example I want to replace the word "cat" with a cat icon and the Strings would be:

"the little cat is good"
"there is no tomorrow" 
"cat is what I need"

and my desired output will be a JScrollPane with the items:

"the little *cat icon* is good"
"there is no tomorrow" 
"*cat icon* is what I need"

What I found are suggestions to create a custom ListCellRenderer to replace the DefaultListModel. In all the examples an imageIcon was added as icon to a lable, unfortunately this only adds one icon at the beginning of the text which is not what I desire.

Here is the relevant part from one of the examples from this site:

@Override
public Component getListCellRendererComponent(
    JList list, Object value, int index, 
    boolean isSelected, boolean cellHasFocus) {

    // Get the renderer component from parent class

    JLabel label = 
        (JLabel) super.getListCellRendererComponent(list, 
            value, index, isSelected, cellHasFocus);

    // Get icon to use for the list item value

    Icon icon = icons.get(value);

    // Set icon to display for value

    label.setIcon(icon);
    return label;
}

So, how can I add an icon inside a text in a JList ?

Any suggestions would be appreciated. Thank you

2
Can you show what entries the icons map contains and the values of the JList ? - Titus
For this example lets say there is one entry in the map with key "cat" and value "cat.png". What values of the JList ? In my current program the JList is "taking" it's values from the DefaultListModel. - artembus
If you've added sentences to the list's model, this won't work, you will have to add individual words. - Titus
Also, you will have to remove the JLabel's text if there is an icon for that value. Something like: if(icon!=null){label.setText("");} - Titus
A JList isn't the right component for what you want to do. You need a JEditorPane or a JTextPane, where you could add icons to the StyledDocument. - Gilbert Le Blanc

2 Answers

3
votes

I would use a JTextPane and the insertIcon(...) method.

See the section from the Swing tutorial on Text Component Features for a working example.

The example just shows how to insert the Icon. It will be up to you to parse the text for the Strings you want to replace. Once you find the String you want to replace you can use code like:

textPane.setSelectionStart(...);
textPane.setSelectionEnd(...);
textPane.replaceSelection(...);
textPane.insertIcon(...);
3
votes

You can use the html features of the JLabel, switching cat to <img src='cat.png'/>

Example

public class JListTest extends JPanel{  
  private static final long serialVersionUID = 1L;

  public JListTest(){
    this.setLayout(new BorderLayout());
    JScrollPane scrollPane = new JScrollPane();
    String[] data = {"the little cat is good", "there is no tomorrow" , "cat is what I need"};
    switchToHtml(data);
    replaceWithImage(data,"cat","cat.png");
    JList<String> list = new JList<String>(data);
    scrollPane.getViewport().add(list);
    this.add(scrollPane,BorderLayout.CENTER);       
  }

  private void replaceWithImage(String[] data, String replace, String image) {
    for (int i = 0; i < data.length; i++) {
        String text = data[i];
        if (text.contains(replace)){
            text = text.replaceAll(replace, "<img src=\"" + JListTest.class.getResource(image) + "\">");
            data[i]=text;
        }           
    }
  }

 private void switchToHtml(String[] data) {
    for (int i = 0; i < data.length; i++) {
        data[i]="<html><body>" + data[i] + "</body></html>";
    }
 }

 public static void main(String[] args) {
    JFrame frame = new JFrame("Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(new BorderLayout());
    frame.getContentPane().add(new JListTest(),BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
 }
}

To test, just add a cat.png in same package as class.

The result (with a nice kitty)

Result