2013/04/15

Add the Function “AutoComplete” in JTextField(2)

In the article Add the Function “AutoComplete” in JTextField,we receive many feedback. One is: “Can you help me, make a search like in facebook? every search there are pictures and text”。 It's not very hard to do this, we can just set the JComboBox's Renderer, By default the Renderer of JComboBox is a JLabel, and the JLabel itself has a function "setIcon", so we can set the Icon to the JLabel, the Code is like this:

cbInput.setRenderer(new DefaultListCellRenderer(){
 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 if(value != null){
 this.setText(value.toString());
 String url = value.toString().replaceAll(" ", "_") + ".png";
 ImageIcon icon = getImageIcon(url, IMAGE_ICON_CACHE);
 if(icon != null){
 this.setIcon(icon);
 }
 }
 return this;
 }
 });


In the "getImageIcon" method ,we cache the images, so it no need create a new ImageIcon every time where the UI is Refreshed, which can improve the response time.


public static ImageIcon getImageIcon(String url,Map<String, ImageIcon> IMAGE_ICON_CACHE) {
 if (url == null) {
 return null;
 }
 if (IMAGE_ICON_CACHE.get(url) == null) {
 ImageIcon image = null;
 InputStream in =ResourceAgent.class.getResourceAsStream(url);
 if (in != null) {
 try {
 byte buffer[] = new byte[in.available()];
 for (int i = 0, n = in.available(); i < n; i++) {
 buffer[i] = (byte) in.read();
 }
 Toolkit toolkit = Toolkit.getDefaultToolkit();
 Image img = toolkit.createImage(buffer);
 image = new ImageIcon(img);
 in.close();
 } catch (IOException ex) {
 ex.printStackTrace();
 return null;
 }
 }
 if (image == null) {
 if (ClassLoader.getSystemResource(url) != null) {
 image = new ImageIcon(ClassLoader.getSystemResource(url));
 } else {
 image = new ImageIcon(url);
 }
 }
 if (image == null) {
 System.err.println("can't load image '" + url + "'");
 } else {
 IMAGE_ICON_CACHE.put(url, image);
 }
 }
 return (ImageIcon) IMAGE_ICON_CACHE.get(url);
 }
Finally, it's like this:
The full code file:
package demo; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; import demo.images.*; public class Test { public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); JFrame frame = new JFrame(); frame.setTitle("Auto Completion Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(200, 200, 500, 400); ArrayList<String> items = new ArrayList<String>(); // Locale[] locales = Locale.getAvailableLocales(); // for (int i = 0; i < locales.length; i++) { // String item = locales[i].getDisplayName(); // items.add(item); // } items.add("China"); items.add("China Hongkong"); items.add("China Taiwan"); items.add("USA"); items.add("Japan"); JTextField txtInput = new JTextField(); setupAutoComplete(txtInput, items); txtInput.setColumns(30); frame.getContentPane().setLayout(new FlowLayout()); frame.getContentPane().add(txtInput, BorderLayout.NORTH); frame.setVisible(true); } private static boolean isAdjusting(JComboBox cbInput) { if (cbInput.getClientProperty("is_adjusting") instanceof Boolean) { return (Boolean) cbInput.getClientProperty("is_adjusting"); } return false; } private static void setAdjusting(JComboBox cbInput, boolean adjusting) { cbInput.putClientProperty("is_adjusting", adjusting); } public static ImageIcon getImageIcon(String url,Map<String, ImageIcon> IMAGE_ICON_CACHE) { if (url == null) { return null; } if (IMAGE_ICON_CACHE.get(url) == null) { ImageIcon image = null; InputStream in =ResourceAgent.class.getResourceAsStream(url); if (in != null) { try { byte buffer[] = new byte[in.available()]; for (int i = 0, n = in.available(); i < n; i++) { buffer[i] = (byte) in.read(); } Toolkit toolkit = Toolkit.getDefaultToolkit(); Image img = toolkit.createImage(buffer); image = new ImageIcon(img); in.close(); } catch (IOException ex) { ex.printStackTrace(); return null; } } if (image == null) { if (ClassLoader.getSystemResource(url) != null) { image = new ImageIcon(ClassLoader.getSystemResource(url)); } else { image = new ImageIcon(url); } } if (image == null) { System.err.println("can't load image '" + url + "'"); } else { IMAGE_ICON_CACHE.put(url, image); } } return (ImageIcon) IMAGE_ICON_CACHE.get(url); } public static void setupAutoComplete(final JTextField txtInput, final ArrayList<String> items) { final DefaultComboBoxModel model = new DefaultComboBoxModel(); final Map<String,ImageIcon> IMAGE_ICON_CACHE = new HashMap<String, ImageIcon>(); final JComboBox cbInput = new JComboBox(model) { public Dimension getPreferredSize() { return new Dimension(super.getPreferredSize().width, 0); } }; setAdjusting(cbInput, false); for (String item : items) { model.addElement(item); } cbInput.setSelectedItem(null); cbInput.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!isAdjusting(cbInput)) { if (cbInput.getSelectedItem() != null) { txtInput.setText(cbInput.getSelectedItem().toString()); } } } }); cbInput.setRenderer(new DefaultListCellRenderer(){ public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if(value != null){ this.setText(value.toString()); String url = value.toString().replaceAll(" ", "_") + ".png"; ImageIcon icon = getImageIcon(url, IMAGE_ICON_CACHE); if(icon != null){ this.setIcon(icon); } } return this; } }); txtInput.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { setAdjusting(cbInput, true); if (e.getKeyCode() == KeyEvent.VK_SPACE) { if (cbInput.isPopupVisible()) { e.setKeyCode(KeyEvent.VK_ENTER); } } if (e.getKeyCode() == KeyEvent.VK_ENTER || e.getKeyCode() == KeyEvent.VK_UP || e.getKeyCode() == KeyEvent.VK_DOWN) { e.setSource(cbInput); cbInput.dispatchEvent(e); if (e.getKeyCode() == KeyEvent.VK_ENTER) { txtInput.setText(cbInput.getSelectedItem().toString()); cbInput.setPopupVisible(false); } } if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { cbInput.setPopupVisible(false); } setAdjusting(cbInput, false); } }); txtInput.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { updateList(); } public void removeUpdate(DocumentEvent e) { updateList(); } public void changedUpdate(DocumentEvent e) { updateList(); } private void updateList() { setAdjusting(cbInput, true); model.removeAllElements(); String input = txtInput.getText(); if (!input.isEmpty()) { for (String item : items) { if (item.toLowerCase().startsWith(input.toLowerCase())) { model.addElement(item); } } } cbInput.hidePopup(); cbInput.setPopupVisible(model.getSize() > 0); setAdjusting(cbInput, false); } }); txtInput.setLayout(new BorderLayout()); txtInput.add(cbInput, BorderLayout.SOUTH); } }
The ResourceAgent class:

package demo.images;


public class ResourceAgent {
}

and at the some folder, put the icons related to the text show on the list.