JComboBox has items, but drop down list blank ?
I have a class called : Customer_Contact_Info_Panel which is a Swing JPanel, inside this class it has a Vector called : Contacts_Id_Vector which holds Customer Ids. Customer_Contact_Info_Panel has several JTextFields and an editable JComboBox where user can enter text info, once the text is entered, the Contacts_Id_Vector is updated with the latest user input.
Customer_Contact_Info_Panel is used inside a first tab of a Jtabbedpane. In a second tab I have this line :
JComboBox Order_Customer_Id_ComboBox=new JComboBox(Customer_Contact_Info_Panel.Contacts_Id_Vector);
Order_Customer_Id_ComboBox is where user can select from a drop down list of the latest Customer Ids.
The problem I have now is : after user entered a new user Id in the first tab and the Customer_Contact_Info_Panel.Contacts_Id_Vector is updated, when he goes to the second tab and click on Order_Customer_Id_ComboBox, it drops down an empty list, I can see it probably has all the list items in it judging from the height of the list, but the text is not showing, the strange thing is that if I just click on the blank drop down list, an item will show up in the Order_Customer_Id_ComboBox, and if I click on it to drop down it again, all the list items will show up, including the latest item entered from the first tab ! I wonder if there is a way to repaint or refresh the Order_Customer_Id_ComboBox so that it can show the items when user first click on it ? Is this a bug in Swing, or is it my fault ?
Using jdk1.6.0
Frank
[1542 byte] By [
Ni_Mina] at [2007-10-3 8:36:07]

> Is this a bug in Swing, or is it my fault ?
If I was a betting person I would say its your fault.
If you need further help then you need to create a [url http://homepage1.nifty.com/algafield/sscce.html]Short, Self Contained, Compilable and Executable, Example Program[/url] (SSCCE) that demonstrates the incorrect behaviour, because I can't guess exactly what you are doing based on the information provided.
And don't forget to use the [url http://forum.java.sun.com/help.jspa?sec=formatting]Code Formatting Tags[/url] so the code retains its original formatting.
OK, good suggestion, here we go :
===========================================================
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class Java_Test extends JPanel
{
static JTabbedPane Tabbed_Pane=new JTabbedPane();
JComboBox Contacts_ComboBox;
Customer_Info_Panel Customer_Info_Panel=new Customer_Info_Panel();
Java_Test()
{
JPanel A_Tab_Panel=new JPanel();
A_Tab_Panel.setPreferredSize(new Dimension(300,200));
A_Tab_Panel.add(Customer_Info_Panel);
JPanel B_Tab_Panel=new JPanel();
B_Tab_Panel.setPreferredSize(new Dimension(300,200));
Contacts_ComboBox=new JComboBox(Customer_Info_Panel.Contacts_Id_Vector);
Contacts_ComboBox.setMaximumRowCount(30);
Contacts_ComboBox.setSelectedIndex(-1);
Contacts_ComboBox.setPreferredSize(new Dimension(129,22));
B_Tab_Panel.add(new JLabel("Select Customer Info From List :"));
B_Tab_Panel.add(Contacts_ComboBox);
Tabbed_Pane.addTab("A : Enter Customer Info",null,A_Tab_Panel,null);
Tabbed_Pane.addTab("B : Use entered info",null,B_Tab_Panel,null);
add(Tabbed_Pane);
setPreferredSize(new Dimension(500,300));
}
public static void main(String[] args)
{
final Java_Test demo=new Java_Test();
Dimension Screen_Size=Toolkit.getDefaultToolkit().getScreenSize();
final JFrame frame=new JFrame("JUninstaller");
frame.add(demo);
frame.addWindowListener(new WindowAdapter()
{
public void windowActivated(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowClosing(WindowEvent e) { System.exit(0); }
public void windowDeactivated(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { demo.repaint(); }
public void windowGainedFocus(WindowEvent e) { demo.repaint(); }
public void windowIconified(WindowEvent e) { }
public void windowLostFocus(WindowEvent e) { }
public void windowOpening(WindowEvent e) { demo.repaint(); }
public void windowOpened(WindowEvent e) { }
public void windowResized(WindowEvent e) { demo.repaint(); }
public void windowStateChanged(WindowEvent e) { demo.repaint(); }
});
frame.pack();
frame.setBounds((Screen_Size.width-demo.getWidth())/2,(Screen_Size.height-demo.getHeight())/2-10,demo.getWidth(),demo.getHeight()+38);
frame.setVisible(true);
}
}
class Customer_Info_Panel extends JPanel
{
Vector<String> Contacts_Id_Vector=new Vector<String>();
JComboBox Contacts_Id_ComboBox=new JComboBox(Contacts_Id_Vector);
Customer_Info_Panel()
{
Contacts_Id_ComboBox=new JComboBox(Contacts_Id_Vector);
Contacts_Id_ComboBox.setMaximumRowCount(30);
Contacts_Id_ComboBox.setSelectedIndex(-1);
Contacts_Id_ComboBox.setEditable(true);
Contacts_Id_ComboBox.setPreferredSize(new Dimension(129,22));
Contacts_Id_ComboBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
String New_Item=Contacts_Id_ComboBox.getSelectedItem()==null?"":Contacts_Id_ComboBox.getSelectedItem().toString().trim();
if (!Contacts_Id_Vector.contains(New_Item)) Contacts_Id_Vector.add(New_Item);
}
});
add(new JLabel("Please Enter Customer Info Below :"));
add(Contacts_Id_ComboBox);
setPreferredSize(new Dimension(270,170));
}
}
===========================================================
Run the program, do the following :
1. In Tab A, enter "abc", hit Enter key, then goto Tab B and see it ? It's there.
2. In Tab A again, enter "xyz", hit enter key, goto Tab B, now drop down the list, nothing is there, but you know there are two items in the list. Just click on the blank list, an item will show up, if you look at the drop down list now, you can see both "abc" and "xyz".
3. In Tab A again, enter "123", hit enter, and goto Tab B, drop down the list, what you see ? Nothing ! Click on the last position on the blank list, you will get "123", and now if you drop down the list again, you will see all 3 items !
Am I doing something wrong ?
Frank
You update a Swing component by updating its Model.
So even though you may create a combo box with a Vector. The Vector should only be used to load initial values into the combo box. Once you've created the combo box you update the values through the Model. So you can use comboBox.getModel(..) to get the real model. However, combo box has a convenience method addItem() that will do this for you.
I couldn't really figure out what you code was doing so I just started over to show you that it works:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class Java_Test extends JPanel
{
Vector Contacts_Id_Vector = new Vector();
JComboBox Contacts_ComboBox;
JComboBox Contacts_Id_ComboBox;
Java_Test()
{
JTabbedPane Tabbed_Pane = new JTabbedPane();
add(Tabbed_Pane);
setPreferredSize(new Dimension(500,300));
// first tab
JPanel A_Tab_Panel=new JPanel();
Tabbed_Pane.addTab("A : Enter Customer Info",null,A_Tab_Panel,null);
A_Tab_Panel.setPreferredSize(new Dimension(300,200));
Contacts_Id_ComboBox = new JComboBox();
Contacts_Id_ComboBox.setEditable(true);
Contacts_Id_ComboBox.setPreferredSize(new Dimension(129,22));
Contacts_Id_ComboBox.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
String New_Item = Contacts_Id_ComboBox.getSelectedItem() == null
? "" : Contacts_Id_ComboBox.getSelectedItem().toString().trim();
if (!Contacts_Id_Vector.contains(New_Item))
{
System.out.println(New_Item);
Contacts_Id_Vector.add(New_Item);
Contacts_ComboBox.addItem( New_Item );
Contacts_ComboBox.setSelectedIndex( -1 );
}
}
});
A_Tab_Panel.add(new JLabel("Please Enter Customer Info Below :"));
A_Tab_Panel.add(Contacts_Id_ComboBox);
// second tab
JPanel B_Tab_Panel=new JPanel();
Tabbed_Pane.addTab("B : Use entered info",null,B_Tab_Panel,null);
B_Tab_Panel.setPreferredSize(new Dimension(300,200));
Contacts_ComboBox=new JComboBox();
Contacts_ComboBox.setPreferredSize(new Dimension(129,22));
B_Tab_Panel.add(new JLabel("Select Customer Info From List :"));
B_Tab_Panel.add(Contacts_ComboBox);
}
public static void main(String[] args)
{
final JFrame frame=new JFrame("JUninstaller");
frame.getContentPane().add( new Java_Test() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
You should learn the standard Java naming conventions. The variable names should be:
contactsIdComboBox
contactsComboBox
aTabPanel
bTabPanel
That is you don't upper case the first character and don't use underscores.
Same for method names.
Thanks for your advice, good point.
The reason I designed it this way is because I want to share the Contacts_Id_Vector inside class Customer_Info_Panel with other parts of the program, the idea is that Contacts_Id_Vector is the commom (shared) data structure, it is entered/modified inside the Contacts_Id_ComboBox of Customer_Info_Panel, while the latest information of Contacts_Id_Vector can be accessed from another combobox in another tab, in this case it's Contacts_ComboBox. Since those two comboboxes share the same Contacts_Id_Vector, I expect the latest information to show up in both of them after one of them is updated. Maybe there is a way to repaint the dropdown list that I need to do somewhere that I'm missing now, it seems both comboboxes contains the correct items in the dropdown list, but just not painting them correctly. Once user clicks on the empty list, it'll repaint itself and display the right content.
So the question is how to programmatically update the UI after changing the combobox ?
Frank
You share the model not the Vector.
I wonder if someone can show me how toimplement combobox model firing all necessary events. In this case how to update the UI of the dropdown list ? Any inspirationfrom class javax.swing.DefaultComboBoxModel ?
> You share the model not the Vector.
I understand what you are saying, but sharing the model only partially works with a JComboBox. According to Zukowski in "The Definitive Guide to Java Swing", "if you share a data model across multiple JComboBox components, there can't be a different selected element within each component. When a component is selected in one, its selected in all. This seems to be a bug in the MVC design of the JComboBox." I can supply code that supports this observation. So, I also tried to share the underlying Vector. It does seem to work, with the problem that the selection list is blank after items are added to the list until another selection is made. If that blind selection is made on the first item, the last item is selected. If an element is removed from the end of the Vector, the "visibility" of the list remains unchanged. So, if a selection is made and two items are added to the end of the Vector, the list is blank (but long enough) until another item is selected or the two removed from the end. I have not found a way to make the items appear after adding items.
> When a component is selected in one, its selected in all. This seems to be a bug in the MVC design of the JComboBox."
I would agree. All other components have a separate SelectionModel. The Model should only store data not the selection.
However, I'm not sure what your requirement is. So I suggest you post a new Thread stating your requirements. It sound like you need the ability to add and remove items from the combo box and you want the changes to propagate to all combo boxes. What happens if you remove an item from one combo box that is currently selected in another combo box?
In that case I guess it should automatically update all the comboBoxes that share this vector and listeners for all those comboBoxes be notified.
Since it's not doing this now, I wonder if there is a way I can do something in my code to make the items in the list appear, such as repaint, validate ... I've tried, but nothing works.
Frank
> In that case I guess it should automatically update
> all the comboBoxes that share this vector and
> listeners for all those comboBoxes be notified.
>
For the simple example illustrated, did you try the following:
Contacts_ComboBox=new JComboBox(Customer_Info_Panel.Contacts_Id_ComboBox.getModel());
Since the Vector is enclosed in ComboBoxModel and the model is shared between the two JComboBoxes, the Vector is shared and it will do what you want in terms of automatic updating. However, because the selection is also shared, the two JComboBoxes will select the same item in the Vector. If this is not desirable, then I think what you may have to do is duplicate the Vector. When the Vector in Customer_Info_Panel is changed, change the one in Contacts_ComboBox., through the model. Its ugly, but I have not found a way to work around the blank pull down list. I have set a break point in the update process and looked at the objects contained in the JComboBox and could not find one that obviously was out of synchronization. A Vector seems to be too low of a level for being shared between the two UIs and one of the intermediate objects appears to be maintaining some memory of how many elements are in the Vector. Because Swing was intending that sharing be done at the model level, it should not be surprising that sharing at a lower level does not work exactly right. In fact, it is surprising that it works as well as it does.
