Search code examples
javaswingjcombobox

Shared data between two comboboxes


I need to share data between two(or maybe more) comboboxes, but I want to choose elements independently. For example, if I choose Object1 in first comboBox, my second ComboBox also chooses Object1, because they have same model(DefaultComboBoxModel and this model also manages chosen objects). But I don't want this behavior. I want to choose objects in my comboBoxes independently. When I choose object in first comboBox my second comboBox shouldn't change.

At this moment I'am thinking about supermodel for two models. Supermodel will send events to submodels and they will update comboboxes data, but not the state. But I think this is not the best way.

Are there more intresting and simple aproaches?

Here is the short code to understand what I mean:

package hello;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
public class Comboboxes extends JFrame
{
private JPanel contentPane;
public static void main(String[] args)
{
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            try
            {
                Comboboxes frame = new Comboboxes();
                frame.setVisible(true);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    });
}

public Comboboxes()
{
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 450, 300);
    contentPane = new JPanel();
    contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(contentPane);
    contentPane.setLayout(null);

    JComboBox one = new JComboBox();
    one.setBounds(10, 11, 414, 26);
    contentPane.add(one);

    JComboBox two = new JComboBox();
    two.setBounds(10, 52, 414, 26);
    contentPane.add(two);

    DefaultComboBoxModel<String> model = new DefaultComboBoxModel<String>();
    model.addElement("Item 1");
    model.addElement("Item 2");
    model.addElement("Item 3");

    one.setModel(model);
    two.setModel(model);
}
}

Solution

  • Write a decorator for your ComboBoxModel. The decorator should manage the selectedItem property, while everything else is managed by the delegate.

    You would then have 1 original model, and place different decorators on the comboboxes:

    DefaultComboBoxModel original = ...;
    
    DecoratedModel firstModel = new DecoratedModel( original );
    JComboBox firstCombo = new JComboBox( firstModel );
    
    DecoratedModel secondModel = new DecoratedModel( original );
    JComboBox secondCombo = new JComboBox( secondModel );
    

    Changes to the data can then be performed on the original model, which will adjust the data in all comboboxes simultaneously

    Note: make sure listeners attached to the decorator receive events with the decorated model as source, and not with the delegate model. This is a common mistake when writing a decorator

    Edit

    An alternative is to have a base data structure which is not a ComboBoxModel and create an implementation of ComboBoxModel which uses that data structure. You can then create different combobox model instances which all share the same data structure.