Win a copy of Murach's Python Programming this week in the Jython/Python forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

dynamic dropdown  RSS feed

 
luri ron
Ranch Hand
Posts: 87
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
i wanted to implement the dynamic dropdown like Google search: based on what type in, the drop down list changes. i overwrote the JComboBox's model to remove the unmatched items and fire a content change event whenever there is a document event to the combo box. however, the dropdown menu doesn't work properly. Even though there is 10 items on the list, the dropdown only display one item with a scrollbar to see others. any suggestion aboug this problem? or any other suggestion to properly implement the dynamic dropdown?
 
Maneesh Godbole
Bartender
Posts: 11445
18
Android Eclipse IDE Google Web Toolkit Java Mac Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You might get better results by using a combination of a JTextField (where the user types) and a JList (to display the possible matches)
 
Brian Cole
Author
Ranch Hand
Posts: 935
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
luri ron wrote:i wanted to implement the dynamic dropdown like Google search: based on what type in, the drop down list changes. i overwrote the JComboBox's model to remove the unmatched items and fire a content change event whenever there is a document event to the combo box. however, the dropdown menu doesn't work properly. Even though there is 10 items on the list, the dropdown only display one item with a scrollbar to see others. any suggestion aboug this problem? or any other suggestion to properly implement the dynamic dropdown?


Manipulating the the combo box's model as you describe sounds like a good approach to me.

Are you saying the elements contained in the combo box are correct, but that not enough of them are displayed without scrolling? If so, take a look at the setMaximumRowCount() method. I'm not sure why only one erebeth would be showing [unless someone had called setMaximumRowCount(1)] but perhaps calling that method may help.
 
luri ron
Ranch Hand
Posts: 87
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
here is my code. i setmaxrowcount to 8, and it still had the same problem. if you run the program, first select a item, hit enter, and then backspace to remove all the letters. you will see that only one item is displayed. if you then click on the down-arrow, the popup menu show the right size. is there anything to do with the preferredsize of the popup menu.... thanks for your help. i am running it with jdk 1.6

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.Serializable;
import java.util.ArrayList;
import javax.swing.AbstractListModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.MutableComboBoxModel;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class LRComboBox
{
public static JComboBox createCB (Object[] items)
{
final LRComboBoxModel cbModel = new LRComboBoxModel (items);
DocumentListener documentListener = new DocumentListener() {
public void changedUpdate(DocumentEvent documentEvent) {
System.err.println ("change update");
doit (documentEvent);
}

public void insertUpdate(DocumentEvent documentEvent) {
System.err.println ("insert update");
doit (documentEvent);
}

public void removeUpdate(DocumentEvent documentEvent) {
System.err.println ("remove update");
doit (documentEvent);
}

private void doit (DocumentEvent documentEvent)
{
Document source = documentEvent.getDocument();
int length = source.getLength();
try
{
final String pattern = source.getText(0, length);
System.err.println("pattern is " + pattern);
cbModel.filter(pattern);
}
catch (BadLocationException badLocationException)
{
System.exit(-1);
}
}
};
System.err.println ("Creating combo box..");
JComboBox bc = new JComboBox (cbModel);
bc.setEditable(true);
Component com = bc.getEditor().getEditorComponent();
JTextField tf = (JTextField) com;
tf.addKeyListener(new LRKeyStrokeListener(bc));
tf.getDocument().addDocumentListener(documentListener);
bc.setMaximumRowCount(8);
return bc;
}

public static void main (String[] args)
{
SwingUtilities.invokeLater(new Runnable () {
public void run ()
{
JFrame frame = new JFrame ("LRComboBox");
String items[] = new String[] {"1A23", "234", "456", "232", "12ACV", "12wed", "64646 23232", "134xsc", "12qas", "7646 2232", "87575 2222", "3434 43232", "23232 5343"};
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add (BorderLayout.CENTER, LRComboBox.createCB (items));
frame.setSize(500,500);
frame.pack();
frame.setVisible(true);
}
});
}
}

class LRComboBoxModel extends AbstractListModel implements MutableComboBoxModel, Serializable
{
private ArrayList<Object> immutableObjects = new ArrayList<Object> ();
private ArrayList<Object> displayedObjects = new ArrayList<Object> ();
private Object selectedObject;
private static final long serialVersionUID = -766074626262654394L;

public LRComboBoxModel(Object[] items) {
for (int i=0; i<items.length; ++i)
{
immutableObjects.add (items[i]);
displayedObjects.add (items[i]);
}
if (items.length > 0) selectedObject = displayedObjects.get (0);
}

@Override
public void addElement(Object obj) {
throw new RuntimeException ("not implemented");
}

@Override
public void insertElementAt(Object obj, int index) {
throw new RuntimeException ("not implemented");
}

@Override
public void removeElement(Object obj) {
throw new RuntimeException ("not implemented");
}

public void filter(String pattern) {
int max = 0;
setSelectedItem(pattern);
displayedObjects = new ArrayList<Object> ();
for (Object obj : immutableObjects)
{
String str = (String) obj;
String lowerStr = str.toLowerCase();
String lowerPat = pattern.toLowerCase();
if (lowerStr.indexOf(lowerPat) >= 0)
{
displayedObjects.add(str);
}
}
max = displayedObjects.size();
fireContentsChanged(this, 0, max);
}

@Override
public void removeElementAt(int index) {
throw new RuntimeException ("not implemented");
}

@Override
public Object getSelectedItem() {
return selectedObject;
}

@Override
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals( anObject )) ||
selectedObject == null && anObject != null) {
selectedObject = anObject;
fireContentsChanged(this, -1, -1);
}
}

@Override
public Object getElementAt(int index) {
if ( index >= 0 && index < displayedObjects.size() )
return displayedObjects.get(index);
else
return null;
}

@Override
public int getSize() {
return displayedObjects.size();
}
}



class LRKeyStrokeListener implements KeyListener
{
private JComboBox lrCB = null;
public LRKeyStrokeListener(JComboBox lrCB) {
this.lrCB = lrCB;
}

@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub

}

@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub

}

@Override
public void keyTyped(KeyEvent e)
{
if ((e.getKeyChar() == KeyEvent.VK_TAB) ||
(e.getKeyChar() == KeyEvent.VK_ESCAPE) ||
(e.getKeyChar() == KeyEvent.VK_ENTER))
{
lrCB.setPopupVisible(false);
}
else
{
if (!lrCB.isPopupVisible()) lrCB.setPopupVisible(true);
}
}
}
 
Campbell Ritchie
Sheriff
Posts: 53750
127
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The code is too long to read in one go, and you have made it more difficult by not using the code button, but I think in the 1.5 seconds I looked at your code, "return null;" flashed past the way one's entire life flashes past as one falls from a tall building.

Did you actually write "return null;"? If you did, why? Think of the sort of problems you can cause to code invoking that method.

Yes, you did write return null; when you ought to have thrown an Exception.
 
Brian Cole
Author
Ranch Hand
Posts: 935
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
luri ron wrote:i setmaxrowcount to 8, and it still had the same problem. if you run the program, first select a item, hit enter, and then backspace to remove all the letters. you will see that only one item is displayed. if you then click on the down-arrow, the popup menu show the right size. is there anything to do with the preferredsize of the popup menu....


First, let me concur with Mr. Ritchie that you should edit your post to surround your code with code tags.

Ok, what you haven't explained in your posts is that you are trying to change the size of the drop-down while it is visible on screen. It's not a preferredSize issue because when it first appears it is the correct size. When the user hits backspace the first time, it shows only one item because there is only one item in the model. As the user continues to hit backspace the model does get populated with additional entries but the size of the drop-down doesn't change because it has already been laid out. (You can try this the other way too. Clear the field, click the arrow to show the drop-down, then start typing. Elements should disappear while you type, but the size of the drop-down should remain tall enough for 8 items.)

The simplest solution might be to convince the drop-down to appear tall enough for 8 items even if the size of the model is less than that. That may not be elegant enough for your needs, though. Or you could try changing how the model works so that instead of including/excluding strings as they match/don't-match that it simply changes the order of the strings (matching ones on top, then non-matching ones).

If you really want the size of the visible drop-down to change as the model size changes, there are things you could try. A simple hack like doing
<pre> if (lrCB.isPopupVisible()) {
lrCB.setPopupVisible(false);
lrCB.setPopupVisible(true);
}
</pre>in your keyPressed() method might be good enough, or you may decide you need something more refined.

[edit: I intended to mention that things might work more smoothly if you call fireIntervalAdded()/fireIntervalRemoved() instead of always fireContentsChanged(). This won't affect this sizing issue, though.]
 
luri ron
Ranch Hand
Posts: 87
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
thanks very much. doing the following does the trick.


i got the same problem with fireintervaladded/fireinterval.
Any good book you suggest for some of the Swing hack like this? thanks
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!