2014-01-16 3 views
3

Приветствуем всех это сообщество gr8 StackOverflow. Это мой первый вопрос, пытаясь решить его сам и, таким образом, долгое время ... :-)
JSpinner не показывает минимальное значение при нажатии стрелки вниз

У меня проблема с получением минимального заданного значения 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 было бы моим последним средством.

+0

Для лучшей помощи рано, опубликовать [MCVE] (http://stackoverflow.com/help/mcve). –

+1

@ Андрю Томпсон: Я действительно не знаю, как сделать его более компактным. Этот пример кода содержит только проблему. – dARKpRINCE

+0

C не означает «компактный». Почему бы не попробовать * прочитать * (один экран полный), а не делать случайные догадки? –

ответ

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; 
    } 
} 
+0

Спасибо за решение. Это работает отлично! Мой вопрос будет, когда я должен отказаться от переопределения метод. Для всех моделей или только выбранных? – dARKpRINCE

Смежные вопросы