Reputation: 9589
I have a JComboBox
populated with information from a file (XML) and I want a second ComboBox
to be populated with information based in the selected item in the first one.
My english is a bit rusty so I'll show you an example, this is my XML file:
<components>
<house id="Kitchen">
<espresso_machine>C</espresso_machine>
<coffee_machine>C</coffee_machine>
<coffee_pot>C</coffee_pot>
<kettle>C</kettle>
<toaster>C</toaster>
<microwave>C</microwave>
<oven>C</oven>
<frying_pan>C</frying_pan>
<stand_mixer>C</stand_mixer>
<extrator_fan>C</extrator_fan>
<tv>C</tv>
<compact_flurescent>C</compact_flurescent>
<flurescent_tube>C</flurescent_tube>
<dishwasher>C</dishwasher>
<freezer>C</freezer>
<blender>C</blender>
<can_opener>C</can_opener>
<cooking_range>C</cooking_range>
<popcorn_popper>C</popcorn_popper>
</house>
<house id="Laundry">
<washing_machine>C</washing_machine>
<clothes_dryer>C</clothes_dryer>
<vacuum_handler>C</vacuum_handler>
<compact_fluorescent>C</compact_fluorescent>
<iron>C</iron>
</house>
<house id="Room">
<compact_fluorescent>C</compact_fluorescent>
<ac_room>C</ac_room>
<tv>C</tv>
<cell_phone_charger>C</cell_phone_charger>
<clock_radio>C</clock_radio>
</house>
</components>
My first combobox has the attribute "id" content (Kitchen, Laundry, Room). The first time I open my JDialog the option "Kitchen" is selected (in the first combobox) and the second combobox has all the sub-elements qualified name (expresso machine, coffee machine, coffee pot, kettle, etc)
I need the content of my second combobox to change when I change the selected item in the first one.
Here's a sample of my code:
houseSpaceCombo = new JComboBox(configs.XMLreaderDOM4J.readHouseTypeID());
equipmentsCombo = new JComboBox(configs.XMLreaderDOM4J.readHouseEquipmentsID(houseSpaceCombo.getSelectedItem().toString()));
and other two methods:
public static String[] readHouseTypeID()
{
Element root = getDoc().getRootElement();
ArrayList<String> attributeAL = new ArrayList<>();
for (Iterator i = root.elementIterator( "house" ); i.hasNext();)
{
Element foo = (Element) i.next();
attributeAL.add(foo.attributeValue("id").toString());
}
String[] vec = convertArrayListToArray(attributeAL);
return vec;
}
public static String[] readHouseEquipmentsID(String selectedItem)
{
Element root = getDoc().getRootElement();
Element innerElement;
ArrayList<String> attributeAL = new ArrayList<>();
for ( Iterator i = root.elementIterator( "house" ); i.hasNext(); ) {
Element element = (Element) i.next();
if(element.attributeValue("id").equals(selectedItem)) {
for ( Iterator j = element.elementIterator(); j.hasNext(); ) {
innerElement = (Element) j.next();
String tmp = innerElement.getQualifiedName().replace("_", " ");
attributeAL.add(tmp);
}
}
}
String[] vec = convertArrayListToArray(attributeAL);
return vec;
}
What can I do?
Upvotes: 0
Views: 1024
Reputation: 347334
I would create a Map
keyed to the id
attribute, which contains a ComboBoxModel
of all the child elements.
When the select item of the first combo box changes, I would simple look up the value in the Map
and set the second combo box's model to the retrieved value
Example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SwitchComboBoxModels {
public static void main(String[] args) {
new SwitchComboBoxModels();
}
public SwitchComboBoxModels() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Map<String, ComboBoxModel> models;
private JComboBox cbMain;
private JComboBox cbSub;
public TestPane() {
models = new HashMap<>(25);
models.put("Kitchen", createComboBoxModel("espresso_machine",
"coffee_machine",
"coffee_pot",
"kettle",
"toaster",
"microwave",
"oven",
"frying_pan",
"stand_mixer",
"extrator_fan",
"tv",
"compact_flurescent",
"flurescent_tube",
"dishwasher",
"freezer",
"blender",
"can_opener",
"cooking_range",
"popcorn_popper"));
models.put("Laundry", createComboBoxModel("washing_machine",
"clothes_dryer",
"vacuum_handler",
"compact_fluorescent",
"iron"));
ComboBoxModel mainModel = createComboBoxModel("Kitchen", "Laundry");
cbMain = new JComboBox();
cbSub = new JComboBox();
cbMain.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cbSub.setModel(models.get((String) cbMain.getSelectedItem()));
}
});
cbMain.setModel(mainModel);
cbSub.setModel(models.get((String) cbMain.getSelectedItem()));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(cbMain, gbc);
add(cbSub, gbc);
}
protected ComboBoxModel createComboBoxModel(String... values) {
return new DefaultComboBoxModel(values);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
}
Additional Example
From your example code, you already have the model in memory. You have two choices at this stage.
You could build a series of ComboBoxModel
s by parsing the in memory document OR you cold dynamically build the models from the XML each time they are changed.
I'd go with parsing the model at the start and caching the results as XML DOM's are memory hungery
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.util.Map;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class SwitchComboBoxModels {
public static void main(String[] args) {
new SwitchComboBoxModels();
}
public SwitchComboBoxModels() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Document xmlDoc;
private JComboBox cbMain;
private JComboBox cbSub;
private XPathFactory xFactory;
private XPath xPath;
public TestPane() {
try {
readModel();
ComboBoxModel mainModel = createComboBoxModelByID(find("/components/house[@id]"));
cbMain = new JComboBox();
cbSub = new JComboBox();
cbMain.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
updateSubModel();
}
});
cbMain.setModel(mainModel);
updateSubModel();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(cbMain, gbc);
add(cbSub, gbc);
} catch (XPathExpressionException | ParserConfigurationException | SAXException | IOException exp) {
exp.printStackTrace();
}
}
protected void updateSubModel() {
try {
String key = (String) cbMain.getSelectedItem();
Node parent = findFirst("/components/house[@id='" + key + "']");
ComboBoxModel subModel = createComboBoxModel(parent.getChildNodes());
cbSub.setModel(subModel);
} catch (XPathExpressionException exp) {
exp.printStackTrace();
}
}
protected void readModel() throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
xmlDoc = factory.newDocumentBuilder().parse(getClass().getResourceAsStream("/Model.xml"));
}
protected NodeList find(String xPathQuery) throws XPathExpressionException {
XPathExpression xExpress = getXPath().compile(xPathQuery);
return (NodeList) xExpress.evaluate(xmlDoc.getDocumentElement(), XPathConstants.NODESET);
}
protected Node findFirst(String xPathQuery) throws XPathExpressionException {
XPathExpression xExpress = getXPath().compile(xPathQuery);
return (Node) xExpress.evaluate(xmlDoc.getDocumentElement(), XPathConstants.NODE);
}
public XPath getXPath() {
if (xPath == null) {
xPath = getXPathFactory().newXPath();
}
return xPath;
}
protected XPathFactory getXPathFactory() {
if (xFactory == null) {
xFactory = XPathFactory.newInstance();
}
return xFactory;
}
public String getAttributeValue(Node nNode, String sAttributeName) {
Node nAtt = nNode.getAttributes().getNamedItem(sAttributeName);
return nAtt == null ? null : nAtt.getNodeValue();
}
protected ComboBoxModel createComboBoxModelByID(NodeList nodeList) {
DefaultComboBoxModel model = new DefaultComboBoxModel();
for (int index = 0; index < nodeList.getLength(); index++) {
Node node = nodeList.item(index);
model.addElement(getAttributeValue(node, "id"));
}
return model;
}
protected ComboBoxModel createComboBoxModel(NodeList nodeList) {
DefaultComboBoxModel model = new DefaultComboBoxModel();
for (int index = 0; index < nodeList.getLength(); index++) {
Node node = nodeList.item(index);
if (node.getNodeType() == 1) {
model.addElement(node.getNodeName());
}
}
return model;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
}
Upvotes: 2