I have a panel containing textfields (red, green, blue) and sliders (red, green, blue). Users are supposed to be able to utilize whichever they prefer, and the corresponding component should update. (E.g., entering 100 into the red textfield should move the red slider to 100).
Since I want the sliders to update as text is being inserted or removed, I created a simple DocumentListener. However, I get the error message "java.lang.IllegalStateException: Attempt to mutate in notification." My program gets confused as to whether it should updated the slider or textfield first. Is there a way to fix this problem? I will post my two classes below, and a photo of the GUI will also be attached for quick reference.
public class ColorChooser extends javax.swing.JPanel implements ChangeListener {
private Vector listeners;
public ColorChooser() {
initComponents();
listeners = new Vector();
sldRed.addChangeListener(this);
sldGreen.addChangeListener(this);
sldBlue.addChangeListener(this);
txtRed.setText("0");
txtGreen.setText("0");
txtBlue.setText("0");
Document docRed = txtRed.getDocument();
docRed.addDocumentListener(new MyDocumentListener(txtRed, sldRed));
Document docGreen = txtGreen.getDocument();
docGreen.addDocumentListener(new MyDocumentListener(txtGreen, sldGreen));
Document docBlue = txtBlue.getDocument();
docBlue.addDocumentListener(new MyDocumentListener(txtBlue, sldBlue));
}
// Variables declaration - do not modify
private javax.swing.JLabel labelBlue;
private javax.swing.JLabel labelGreen;
private javax.swing.JLabel labelRed;
private javax.swing.JSlider sldBlue;
private javax.swing.JSlider sldGreen;
private javax.swing.JSlider sldRed;
private jcolorchooser.JColorIntegerField txtBlue;
private jcolorchooser.JColorIntegerField txtGreen;
private jcolorchooser.JColorIntegerField txtRed;
// End of variables declaration
@Override
public void stateChanged(ChangeEvent ce) {
if (ce.getSource() == sldRed) {
txtRed.setText(Integer.toString(sldRed.getValue()));
}
if (ce.getSource() == sldGreen) {
txtGreen.setText(Integer.toString(sldGreen.getValue()));
}
if (ce.getSource() == sldBlue) {
txtBlue.setText(Integer.toString(sldBlue.getValue()));
}
int r = sldRed.getValue();
int g = sldGreen.getValue();
int b = sldBlue.getValue();
Color color = new Color(r,g,b);
fireColorEvent(new ColorEvent(this,color));
}
private void fireColorEvent(ColorEvent colorEvent){
Vector v;
synchronized(this){
v = (Vector)listeners.clone();
}
int size = v.size();
for(int i=0; i<size; i++){
ColorListener colorListener = (ColorListener)v.elementAt(i);
colorListener.changeColor(colorEvent);
}
}
public void addColorListener(ColorListener colorListener){
listeners.addElement(colorListener);
}
public void removeColorListener(ColorListener colorListener){
listeners.removeElement(colorListener);
}
}
//DocumentListener Class
public class MyDocumentListener implements DocumentListener {
private JColorIntegerField jColorIntegerField;
private JSlider jColorSlider;
public MyDocumentListener(JColorIntegerField jColorIntegerField,
JSlider jColorSlider) {
this.jColorIntegerField = jColorIntegerField;
this.jColorSlider = jColorSlider;
}
public void insertUpdate(DocumentEvent de) {
if (jColorIntegerField.getText().equals("")) {
jColorSlider.setValue(0);
}
else {
jColorSlider.setValue(Integer.parseInt(
jColorIntegerField.getText()));
}
}
@Override
public void removeUpdate(DocumentEvent de) {
if (jColorIntegerField.getText().equals("")) {
jColorSlider.setValue(0);
}
else {
jColorSlider.setValue(Integer.parseInt(
jColorIntegerField.getText()));
}
}
@Override
public void changedUpdate(DocumentEvent de) {
}
}
This may come a little late, but I was working on a Java project this week and I had the same issue as the one you described above.
While searching for a solution, I stumbled upon your question. As it doesn't have an answer yet, I thought it could be helpful to come back here and describe how I solved the problem (maybe it will help you or someone else in the future).
So, it seems that the Swing API helps us here by offering a very nice method named getValueIsAdjusting. This method is part of the
JSliderclass.We modify the
stateChangedmethod from theChangeListenerimplementation:The
if (source.getValueIsAdjusting())instruction makes thesetText's happen only if you are still "adjusting" the slider (that means you are still dragging it with the mouse).Writing a value into the
JTextFieldwill trigger thestateChangedmethod from the sliders, but it will NOT call thesetText's, because the slider value is not "adjusting".Thus, you get rid of the exception.