First, let me discuss the data model :
I've compiled an HL7 definition in an tree-like object model, with 3 levels : Segment, Element and Subelement. The segment contains a List, and the Element contains a List. The relationship between those is kinda like "Continent-Country-City"
Second, i've created a GUI component composed of 3 combobox, each having a different ComboBoxModel accessing the object model described earlier.
I've applied the Observer pattern on the ComboBoxModel, so that each model is aware of which List<> it has to access :
- the HL7DefinitionElementModel observes the HL7DefinitionSegmentModel
- the HL7DefinitionSubelementModel observes the HL7DefinitionElementModel
When you pick a value in the first combobox (the Segment), the HL7DefinitionElementModel updates and store which Segment have been picked. The data is correctly stored. The first value is correctly displayed in the "closed" JComboBox. But when you try to open that JComboBox (the Element), if the number of elements is too big (around 12), the items in the invoked Popup Menu are blank.
I'll gladly post any code. I could send the entire project if needed, but haven't been able to reduce it to a SSCEE.
EDIT : here is an illustration of the problem
(http://imgur.com/AiJ8mu0)
EDIT : here is an SSCCE :
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.event.ListDataListener;
public class Application extends JFrame {
/**
*
*/
private static final long serialVersionUID = -2517616123689799182L;
public Application() {
add(new HL7FieldSelector());
}
public static void main(String[] args) {
Application a = new Application();
a.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
a.setSize(new Dimension(400, 100));
a.setVisible(true);
}
}
class HL7FieldSelector extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 6135074279269049773L;
private JComboBox<HL7DefinitionSegment> segment;
private JComboBox<HL7DefinitionElement> element;
private HL7DefinitionSegmentModel segmentModel;
private HL7DefinitionElementModel elementModel;
public HL7FieldSelector() {
segment = new JComboBox<HL7DefinitionSegment>();
element = new JComboBox<HL7DefinitionElement>();
segmentModel = new HL7DefinitionSegmentModel();
elementModel = new HL7DefinitionElementModel();
segmentModel.addObserver(elementModel);
segment.setModel(segmentModel);
element.setModel(elementModel);
segment.addActionListener(this);
element.addActionListener(this);
initUI();
}
private void initUI() {
this.setLayout(new GridLayout(1, 3));
this.add(segment);
this.add(element);
this.setMinimumSize(new Dimension(500, 30));
this.setPreferredSize(new Dimension(500, 30));
this.setMaximumSize(new Dimension(500, 30));
segment.setMaximumRowCount(10);
element.setMaximumRowCount(10);
}
@Override
public void actionPerformed(ActionEvent arg0) {
setVisible(!isVisible());
setVisible(!isVisible());
}
}
class HL7DefinitionSegment implements Comparable<HL7DefinitionSegment>, Serializable {
/**
*
*/
private static final long serialVersionUID = 7922798285885405647L;
private List<HL7DefinitionElement> elements;
private String name;
public HL7DefinitionSegment(String name, ArrayList<HL7DefinitionElement> elements) {
this.name = name;
this.elements = elements;
}
public HL7DefinitionSegment() {
elements = new Vector<HL7DefinitionElement>();
}
public boolean addElement(HL7DefinitionElement element) {
return elements.add(element);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<HL7DefinitionElement> getElements() {
return elements;
}
@Override
public String toString() {
return this.name;
}
@Override
public int compareTo(HL7DefinitionSegment segment) {
return name.compareTo(segment.getName());
}
}
class HL7DefinitionElement implements Comparable<HL7DefinitionElement>, Serializable {
/**
*
*/
private static final long serialVersionUID = -5344721929162039227L;
private String name;
private String number;
public HL7DefinitionElement(String name, String number) {
this.name = name;
this.number = number;
}
public HL7DefinitionElement() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@Override
public String toString() {
return number + " " + name;
}
@Override
public int compareTo(HL7DefinitionElement element) {
return number.compareTo(element.getNumber());
}
}
class HL7DefinitionModel implements Serializable {
/**
*
*/
private static final long serialVersionUID = -8180582371776223436L;
private List<HL7DefinitionSegment> segments;
private static HL7DefinitionModel _instance;
public HL7DefinitionModel(Vector<HL7DefinitionSegment> segments) {
this.segments = segments;
}
public HL7DefinitionModel() {
segments = new Vector<HL7DefinitionSegment>();
}
public boolean addSegment(HL7DefinitionSegment segment) {
return segments.add(segment);
}
public List<HL7DefinitionSegment> getSegments() {
return segments;
}
public void setSegments(List<HL7DefinitionSegment> segments) {
this.segments = segments;
}
public static HL7DefinitionModel getInstance() {
if (_instance == null) {
_instance = new HL7DefinitionModel();
for (int i = 0; i < 2; i++) {
HL7DefinitionSegment s = new HL7DefinitionSegment();
s.setName("SEG" + i);
for (int j = 0; j < 20; j++) {
s.addElement(new HL7DefinitionElement("" + j + j + j, "" + j));
}
_instance.addSegment(s);
}
}
return _instance;
}
}
class HL7DefinitionSegmentModel extends Observable implements javax.swing.ComboBoxModel<HL7DefinitionSegment> {
private HL7DefinitionModel model;
private HL7DefinitionSegment selectedItem;
public HL7DefinitionSegmentModel() {
this.model = HL7DefinitionModel.getInstance();
this.selectedItem = getElementAt(0);
}
public void addListDataListener(ListDataListener l) {}
public void removeListDataListener(ListDataListener l) {}
@Override
public HL7DefinitionSegment getElementAt(int index) {
return model.getSegments().get(index);
}
@Override
public int getSize() {
return model.getSegments().size();
}
@Override
public Object getSelectedItem() {
return selectedItem;
}
@Override
public void setSelectedItem(Object anItem) {
this.selectedItem = (HL7DefinitionSegment) anItem;
setChanged();
notifyObservers();
}
}
class HL7DefinitionElementModel extends Observable implements javax.swing.ComboBoxModel<HL7DefinitionElement>, Observer {
private HL7DefinitionSegment segment;
private HL7DefinitionElement selectedItem;
public HL7DefinitionElementModel() {
this.segment = null;
}
@Override
public void update(Observable o, Object arg1) {
if (o instanceof HL7DefinitionSegmentModel) {
segment = (HL7DefinitionSegment) ((HL7DefinitionSegmentModel) o).getSelectedItem();
setSelectedItem(getElementAt(0));
}
}
public void addListDataListener(ListDataListener l) {}
public void removeListDataListener(ListDataListener l) {}
@Override
public HL7DefinitionElement getElementAt(final int index) {
return segment.getElements().get(index);
}
@Override
public int getSize() {
return (segment != null ? segment.getElements().size() : 0);
}
@Override
public Object getSelectedItem() {
return selectedItem;
}
@Override
public void setSelectedItem(Object anItem) {
this.selectedItem = (HL7DefinitionElement) anItem;
setChanged();
notifyObservers();
}
}
To reproduce the error :
- Launch the application
- Click on second combobox
- Click on the first, select option 2
- Click on second combobox
- Notice how the list is empty
if you do :
- Launch the application
- Click on the first combobox, select option 2
- Click on second combobox
- Notice how the list is populated
EDIT : Here is something else that I've found : The popup menu is only blank if there is more elements in it than in the initial "fill". That is, if the combobox is filled with 20 elements in the first pick, on the next picks the popup menu will be blank if the number of elements is 21 or more, displayed if the number of elements is 20 or less.