按下箭头时,JSpinner未显示最小值

时间:2014-01-16 09:34:20

标签: java swing jspinner

向所有这个gr8 StackOverflow社区致以问候。这是我自己尝试解决之后的第一个问题因此有点长...... :-)

我在使用向下箭头键获取JSpinner的最小指定值时遇到问题。它接受在文本字段中键入的值。其他一切都很好。奇怪的是,这只发生在Spinner模型的某些组合中,特别是new SpinnerNumberModel(29.6, 29.6, 118.1, 0.1)new SpinnerNumberModel(2.00, 2.00, 6.00, 0.01)。下面是有问题的2 JSpinners的代码。我不确定为什么这些模型会产生问题,如果有更多的模型出现这个问题。

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;

public class JSpinnerBug {

    private JFrame frame;
    private JSpinner spinner;
    private JSpinner spinner_1;
    private JButton btnChangeValue_1;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JSpinnerBug window = new JSpinnerBug();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public JSpinnerBug() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        GridBagLayout gridBagLayout = new GridBagLayout();
        gridBagLayout.columnWidths = new int[]{119, 88, 105, 0};
        gridBagLayout.rowHeights = new int[]{25, 0, 0};
        gridBagLayout.columnWeights = new double[]{0.0, 0.0, 0.0, Double.MIN_VALUE};
        gridBagLayout.rowWeights = new double[]{0.0, 0.0, Double.MIN_VALUE};
        frame.getContentPane().setLayout(gridBagLayout);

        JButton btnChangeValue = new JButton("Change Value");
        btnChangeValue.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                spinner.setValue(2.00);
            }
        });

        spinner = new JSpinner();
        spinner.setModel(new SpinnerNumberModel(2.01, 2.00, 6.00, 0.01));
        GridBagConstraints gbc_spinner = new GridBagConstraints();
        gbc_spinner.fill = GridBagConstraints.HORIZONTAL;
        gbc_spinner.insets = new Insets(0, 0, 5, 5);
        gbc_spinner.gridx = 1;
        gbc_spinner.gridy = 0;
        frame.getContentPane().add(spinner, gbc_spinner);
        GridBagConstraints gbc_btnChangeValue = new GridBagConstraints();
        gbc_btnChangeValue.insets = new Insets(0, 0, 5, 0);
        gbc_btnChangeValue.anchor = GridBagConstraints.NORTHWEST;
        gbc_btnChangeValue.gridx = 2;
        gbc_btnChangeValue.gridy = 0;
        frame.getContentPane().add(btnChangeValue, gbc_btnChangeValue);

        spinner_1 = new JSpinner();
        spinner_1.setModel(new SpinnerNumberModel(29.7, 29.6, 118.1, 0.1));
        GridBagConstraints gbc_spinner_1 = new GridBagConstraints();
        gbc_spinner_1.fill = GridBagConstraints.HORIZONTAL;
        gbc_spinner_1.insets = new Insets(0, 0, 0, 5);
        gbc_spinner_1.gridx = 1;
        gbc_spinner_1.gridy = 1;
        frame.getContentPane().add(spinner_1, gbc_spinner_1);

        btnChangeValue_1 = new JButton("Change Value");
        btnChangeValue_1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                spinner_1.setValue(29.6);
            }
        });
        GridBagConstraints gbc_btnChangeValue_1 = new GridBagConstraints();
        gbc_btnChangeValue_1.gridx = 2;
        gbc_btnChangeValue_1.gridy = 1;
        frame.getContentPane().add(btnChangeValue_1, gbc_btnChangeValue_1);
    }

/**
 * Custom Spinner to detect button click on 
 * JSpinner. This class fixes a bug for 
 * JSpinner like for example for minimum value = 2.00 
 * and step size 0.01
 * 
 * @author dARKpRINCE
 *
 */
class CustomSpinner extends JSpinner{

        @Override
        public Object getPreviousValue() {
            // Circumvent JSpinner bug
            NumberEditor spinnerEditor = (NumberEditor) this.getEditor();
            SpinnerNumberModel model = spinnerEditor.getModel();
            if(model.getMinimum().equals(2.00) && model.getStepSize().equals(0.01)){
                if ((Double) getValue() == 2.01) {
                    return 2.00;
                }
                else {
                    return super.getPreviousValue();
                }
            }
            else if(model.getMinimum().equals(29.6) && model.getStepSize().equals(0.1)){
                if ((Double) getValue() == 29.7) {
                    return 29.6;
                }
                else {
                    return super.getPreviousValue();
                }
            }
            else {
                return super.getPreviousValue();
            }
        }
    }    

}

您可以尝试使用new SpinnerNumberModel(55.3, 55.3, 118.1, 0.1)等其他模型。有了它就行了。

我的解决方案是扩展JSpinner(在代码示例的末尾给出)并参与创建此问题的每个模型,这不是最佳的。因此,每个JSpinner都被CustomSpinner取代。

我还检查了JSpinner的源代码,但无法确定/解决问题。任何人都可以告诉我这是一个错误,以及如何最佳地修复它?使用JSpinner的第三方库是我的最后手段。

1 个答案:

答案 0 :(得分:2)

BigDecimal#compareTo(...)中的

Double#compareTo(...)

import java.awt.*;
import java.math.*;
import javax.swing.*;
public class JSpinnerBug2 {
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        try {
          JFrame frame = new JFrame();
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.getContentPane().add(new JSpinnerBug2().makeUI());
          frame.setSize(320, 240);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }
  public JComponent makeUI() {
    Box box = Box.createVerticalBox();
    box.add(new JSpinner(new SpinnerNumberModel(2.01, 2.00, 6.00, 0.01)));
    box.add(Box.createVerticalStrut(10));
    box.add(new JSpinner(new SpinnerNumberModel(29.7f, 29.6f, 111.8f, 0.1f)));
    box.add(Box.createVerticalStrut(10));
    box.add(new JSeparator());

    //TEST:
    double d = 29.7 - 29.6 - 0.1;
    System.out.format("(%f-%f-%f>=0): %b%n", 29.7, 29.6, 0.1, d>=0);
    System.out.format("(abs(%f-%f-%f)<1.0e-14): %b%n", 29.7, 29.6, 0.1, Math.abs(d)<1.0e-14);
    System.out.format("(abs(%f-%f-%f)<1.0e-15): %b%n", 29.7, 29.6, 0.1, Math.abs(d)<1.0e-15);

    box.add(new JSpinner(new SpinnerNumberModel(2.01f, 2.00f, 6.00f, 0.01f)));
    box.add(Box.createVerticalStrut(10));
    box.add(new JSpinner(new SpinnerNumberModel(29.7, 29.6, 111.8, 0.1) {
      @Override public Object getPreviousValue() {
        Number v = getNumber();
        BigDecimal value    = new BigDecimal(v.toString());
        BigDecimal stepSize = new BigDecimal(getStepSize().toString());
        BigDecimal maximum  = new BigDecimal(getMaximum().toString());
        BigDecimal minimum  = new BigDecimal(getMinimum().toString());
        BigDecimal newValue;
        if (v instanceof Double) {
          newValue = value.subtract(stepSize);
        } else {
          return super.getPreviousValue();
        }
        if ((maximum != null) && (maximum.compareTo(newValue) < 0)) {
          return null;
        }
        if ((minimum != null) && (minimum.compareTo(newValue) > 0)) {
          return null;
        } else {
          return newValue;
        }
      }
    }));
    box.add(Box.createVerticalGlue());
    box.setBorder(BorderFactory.createEmptyBorder(20,20,20,20));
    return box;
  }
}