The default behavior of a JList is that when you use the keyboard to press the first character of a list item, the selection will jump to the first item starting with that letter. Additional presses of the same letter will cycle through all the items starting with the same letter.
For a small list, this functionality works great. For a larger list with hundreds of items however, you may not want to press a single key thirty times to get to the item you are looking for.
So I did a little research about how to make the list work more like windows, where if you type quickly, it will navigate to the item in the list that starts with the prefix selected. So you could type the first few characters of the item to jump much closer to or exactly on the item you are trying to reach.
It turns out this is not difficult but it requires a bit of boilerplate code. My example code here is a modified version of some example code released under the GNU license.
One of the keys to making this work is you need to define how long between key-presses should the system interpret the new keypress as a starting a new search vs. adding additional characters to the original search. CHAR_DELTA
in this example code defines how long the system will wait between keypresses before presuming you’re starting a new search, here we are saying you have to type at least one key per second (1000ms) to add additional letters to your search. m_key
is needed to track what key sequence has been typed so far, and m_time
tracks the time of the last key-press in order to identify whether the threshold of time has elapsed to make this a new search.
//elsewhere: jList1 = new javax.swing.JList(); private static int CHAR_DELTA = 1000; private String m_key; private long m_time; private void keyPressHandler(java.awt.event.KeyEvent evt) { char ch = evt.getKeyChar(); //ignore searches for non alpha-numeric characters if (!Character.isLetterOrDigit(ch)) { return; } // reset string if too much time has elapsed if (m_time+CHAR_DELTA < System.currentTimeMillis()) { m_key = ""; } m_time = System.currentTimeMillis(); m_key += Character.toLowerCase(ch); // Iterate through items in the list until a matching prefix is found. // This technique is fine for small lists, however, doing a linear // search over a very large list with additional string manipulation // (eg: toLowerCase) within the tight loop would be quite slow. // In that case, pre-processing the case-conversions, and storing the // strings in a more search-efficient data structure such as a Trie // or a Ternary Search Tree would lead to much faster find. for (int i=0; i < jList1.getModel().getSize(); i++) { String str = ((String)jList1.getModel().getElementAt(i)).toLowerCase(); if (str.startsWith(m_key)) { jList1.setSelectedIndex(i); //change selected item in list jList1.ensureIndexIsVisible(i); //change listbox scroll-position break; } } }
Wow, this is exactly what I needed. I had to change
jList1.setSelectedIndex(i);
to
jList1.setSelectedIndex(i-1);
Ohterwise it worked like a charm! Thank you!
(Charlotte from Sweden)