如何根据当前编辑的字段内容更改JSpinner的背景颜色?

时间:2017-07-02 13:10:42

标签: java swing listener jspinner

我使用JSpinner使用SpinnerNumberModel使用double值的GUI。

当我更改Editor的{​​{1}}的内容时,我希望背景更改为黄色(以显示当前显示的值不是“已保存”的值JSpinner分别为JSpinner

如果该内容无效(例如,超出我的Model指定的允许范围或文字为“abc”),则背景应更改为红色。

我试图通过SpinnerNumberModel实现我想要的但尚未成功,我也不确定它是否能够正常工作,因为我需要检查聚焦和散焦之间的内容。< / p>

我查看了FocusListener组件存在的所有Listeners的教程,但找不到适合该作业的正确教程。 (here I informed myself

我是Swing概念的新手,非常感谢能让我更接近解决问题的任何帮助,同时也帮助我们更好地理解Listeners以及如何更好地使用它们! / p>

我的真正基本代码示例,提到使用焦点监听器的不良尝试:

Listeners

3 个答案:

答案 0 :(得分:2)

JSpinner使用文本字段作为微调器的编辑器

因此,您可以将DocumentListener添加到用作编辑器的文本字段的Document

类似的东西:

JTextField textField = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField());
textField.getDocument.addDocumentListener(...);

然后,当添加/删除文本时,将生成DocumentEvent,您可以进行错误检查。阅读Listener For Changes on a Document上Swing教程中的部分,了解更多信息和工作示例。

答案 1 :(得分:1)

您可以使用CaretListener,这是一个开始:

import java.awt.Color;
import java.awt.Component;
import javax.swing.BoxLayout;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

public class SpinerTest{

    JSpinner spinner;

    public SpinerTest() {
        JFrame frame = new JFrame("frame");
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(300, 200);
        frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
        SpinnerNumberModel model = new SpinnerNumberModel(0., 0., 100., 0.1);
        spinner = new JSpinner(model);
        setCaretListener();
        frame.getContentPane().add(spinner);
        frame.pack();
        frame.setVisible(true);
    }

    private void setCaretListener() {

        for(Component c : spinner.getEditor().getComponents()) {

            JFormattedTextField field =(JFormattedTextField) c;

            field.addCaretListener(new CaretListener(){
                @Override
                public void caretUpdate(CaretEvent ce) {

                    if (field.isEditValid()) {
                        //add aditional test as needed
                        System.out.println("valid Edit Entered " + field.getText());
                        field.setBackground(Color.WHITE);
                    }
                    else                {
                        System.out.println("Invalid Edit Entered" + field.getText());
                        field.setBackground(Color.PINK);
                    }
                }
            });

        }
    }

    public static void main(String[] args) {

        new SpinerTest();
    }
}

答案 2 :(得分:0)

我能够通过KeyListenerDocumentListenerFocusListener的组合来完成任务。解决方案可能不是最简单的,但最后我编码了。这样可行。附加文件中的注释应该解释我是如何处理这个问题的。

我使用CommaReplacingNumericDocumentFilter expands DocumentFilter class扩展了原始任务,这不是我写的,我从教授那里得到了代码并仅根据我的需要进行了编辑。现在只有数字减去 e E 被接受为JSpinner中的条目。 逗号 替换 dot

<强>代码:

import java.awt.*;
import java.awt.event.*;
import java.util.Locale;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;


public class test implements DocumentListener, ChangeListener, KeyListener{
    boolean keyPressed;
    JFrame frame;   
    SpinnerNumberModel model;
    JSpinner spinner;
    JComponent comp;
    JFormattedTextField field;

public test() {
    JFrame frame = new JFrame("frame");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));

    model = new SpinnerNumberModel(0., 0., 100000., .1);
    spinner = new JSpinner(model);

    //disable grouping for spinner
    JSpinner.NumberEditor editor = new JSpinner.NumberEditor(spinner);
    editor.getFormat().setGroupingUsed(false);
    spinner.setEditor(editor);

    comp = spinner.getEditor();
    field = (JFormattedTextField) comp.getComponent(0);
    field.getDocument().addDocumentListener(this);
    field.addKeyListener(this);
    spinner.addChangeListener(this);

    frame.getContentPane().add(spinner);
    frame.pack();
    frame.setVisible(true);
}

@Override
public void insertUpdate(DocumentEvent e) {
    DocumentEventHandler(e);
}

@Override
public void removeUpdate(DocumentEvent e) {
    DocumentEventHandler(e);
}

@Override
public void changedUpdate(DocumentEvent e) {
    DocumentEventHandler(e);
}

public static boolean isNumeric(String str)  
{  
  try  
  {  
    double d = Double.parseDouble(str);  
  }  
  catch(NumberFormatException nfe)  
  {  
    return false;  
  }  
  return true;  
}

public static void main(String[] args) {
    //to get the right format for double precision numbers
    Locale.setDefault(Locale.US);
    test test = new test();
}

@Override
public void stateChanged(ChangeEvent e) {
    System.out.println("valuechanged: " + spinner.getValue().toString());
    if(keyPressed) {
        field.setBackground(Color.WHITE);
    }
    keyPressed = false;
}

public void DocumentEventHandler(DocumentEvent e) {
    //as soon as update is inserted, set background to yellow
    if (keyPressed) {
        field.setBackground(Color.YELLOW);  

        //check if input is numeric and in bounds
        String text = field.getText();
        if (isNumeric(text)) {
            double value = Double.parseDouble(text);
            if (value < (Double)model.getMinimum() || value > (Double)model.getMaximum()) {
                field.setBackground(Color.RED);
            }
        }
        else { //set background to red
            field.setBackground(Color.RED);
        } 
    }

    keyPressed = false;

    //System.out.println(e.toString());
    //System.out.println("Text: " + field.getText());
}

@Override
public void keyTyped(KeyEvent e) {
    // TODO Auto-generated method stub

}

@Override
public void keyReleased(KeyEvent e) {
    // TODO Auto-generated method stub

}

 /** If not done yet, replaces the DocumentFilter with one replacing commas by decimal points.
    *  This can't be done at the very beginning because the DocumentFilter would be changed to a
    *  javax.swing.text.DefaultFormatter$DefaultDocumentFilter when setting up the JSpinner GUI. */
   public void keyPressed(KeyEvent e) {
       PlainDocument document = (PlainDocument)(field.getDocument());
       if(!(document.getDocumentFilter() instanceof CommaReplacingNumericDocumentFilter))
           document.setDocumentFilter(new CommaReplacingNumericDocumentFilter());
       /*Tell the other handlers that a key has been pressed and the change in the document does
        * not come from using the JSpinner buttons or the MouseWheel.
        */
       keyPressed = true;
   }



}

/** A javax.swing.text.DocumentFilter that replaces commas to decimal points
 *  and ignores non-numeric characters except 'e' and 'E'. This is called before
 *  modi */
class CommaReplacingNumericDocumentFilter extends DocumentFilter {
    @Override
    public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr)
            throws BadLocationException {
    text = filter(text);
    if (text.length() > 0)
        super.insertString(fb, offset, text, attr);
}

@Override
public void replace(FilterBypass fb, int offset, int length, String text,
    AttributeSet attrs) throws BadLocationException {
    text = filter(text);
    if (text.length() > 0)
        super.replace(fb, offset, length, text, attrs);
}

String filter(String text) {
    return text.replace(',', '.').replaceAll("[^0-9eE.-]","");
}
}