JTextField 和 JSlider 之间的交互 ​​- DocumentListener 感到困惑

Posted

技术标签:

【中文标题】JTextField 和 JSlider 之间的交互 ​​- DocumentListener 感到困惑【英文标题】:Interaction between JTextField and JSlider - DocumentListener gets confused 【发布时间】:2017-08-27 22:21:49 【问题描述】:

我有一个包含文本字段(红色、绿色、蓝色)和滑块(红色、绿色、蓝色)的面板。用户应该能够使用他们喜欢的任何一个,并且相应的组件应该更新。 (例如,在红色文本字段中输入 100 应将红色滑块移动到 100)。

由于我希望滑块在插入或删除文本时更新,因此我创建了一个简单的 DocumentListener。但是,我收到错误消息“java.lang.IllegalStateException: Attempt to mutate in notification”。我的程序对是否应该首先更新滑块或文本字段感到困惑。有没有办法解决这个问题?我将在下面发布我的两个课程,并附上GUI的照片以供快速参考。

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) 

    

【问题讨论】:

【参考方案1】:

这可能来得有点晚,但我这周在做一个 Java 项目,遇到了和你上面描述的一样的问题。

在寻找解决方案时,我偶然发现了您的问题。由于它还没有答案,我认为回到这里并描述我是如何解决问题的可能会有所帮助(也许它会对您或将来的其他人有所帮助)。

因此,Swing API 似乎通过提供一个名为getValueIsAdjusting 的非常好的方法来帮助我们。此方法是JSlider 类的一部分。

这如何解决问题?

我们从ChangeListener 实现修改stateChanged 方法:

@Override
public void stateChanged(ChangeEvent ce) 
    JSlider source = (JSlider)ce.getSource();

    if (source.getValueIsAdjusting()) 
        if (source == sldRed)
            txtRed.setText(Integer.toString(sldRed.getValue()));
        else if (source == sldGreen)
            txtGreen.setText(Integer.toString(sldGreen.getValue()));
        else if (source == 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));

if (source.getValueIsAdjusting()) 指令使setText 仅在您仍在“调整”滑块时发生(这意味着您仍在用鼠标拖动它)。

将值写入JTextField 将触发滑块的stateChanged 方法,但它会调用setText,因为滑块值不是“调整” .

因此,您摆脱了异常。

【讨论】:

以上是关于JTextField 和 JSlider 之间的交互 ​​- DocumentListener 感到困惑的主要内容,如果未能解决你的问题,请参考以下文章

JTextField 和 JTextPane 之间的根本区别是啥?

改变 JSlider 的外观和感觉

在几秒钟后自动更改 jSlider [重复]

lwjgl 通过 JSlider 更新 VBO(颜色、顶点)

如何将 JSlider 设置为音频文件的持续时间?

JSlider getX(), getY()