Well you can do this by adding and removing the listener for each of its invocations from the corresponding component. So you need to keep a reference of the shared listener like the following sample code:
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class SpinnerAndSlider extends JPanel {
public static void main(final String args[]) {
SwingUtilities.invokeLater(() -> {
final JSlider slider = new JSlider();
final JSpinner spinner = new JSpinner(new SpinnerNumberModel(slider.getValue(), slider.getMinimum(), slider.getMaximum(), 1));
final ChangeListener listener = new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent cevt) {
if (cevt.getSource() == spinner) {
slider.removeChangeListener(this);
slider.setValue((Integer) spinner.getValue());
slider.addChangeListener(this);
}
else if (cevt.getSource() == slider) {
spinner.removeChangeListener(this);
spinner.setValue(slider.getValue());
spinner.addChangeListener(this);
}
}
};
slider.addChangeListener(listener);
spinner.addChangeListener(listener);
final JPanel contents = new JPanel(); //FlowLayout.
contents.add(slider);
contents.add(spinner);
final JFrame f = new JFrame("Spinner with Slider");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(contents);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
Of course you could also implement it with two different instances (each one of a separate subclass of ChangeListener
) and then, after creation, assign with a setter for example the other component which is supposedly linked.
Or you could use boolean flags in the instances of the ChangeListener
(for the one to know when it is called by the other) instead of having to remove and then adding back again each time the listener to the components.