Java JSpinner:如何同时显示数字和文本?

Java JSpinner:如何同时显示数字和文本?,java,swing,jspinner,Java,Swing,Jspinner,我想创建一个JSpinner,它可以在指定的最小值和指定的最大值之间取所有可能的双值 此外,JSpinner应该能够显示文本,而不是特定的值。假设我们的JSpinner可以取-1到10之间的值。我想显示一个文本,例如“Auto”,而不是-1 如何替换为 这是我编写的模型,但似乎还不够,因为它在JSpinner中说有一个错误,因为文本不是Double public class SpinnerSpecialModel extends AbstractSpinnerModel imp

我想创建一个JSpinner,它可以在指定的最小值和指定的最大值之间取所有可能的
双值

此外,JSpinner应该能够显示文本,而不是特定的值。假设我们的JSpinner可以取-1到10之间的值。我想显示一个文本,例如“Auto”,而不是-1

如何替换为

这是我编写的模型,但似乎还不够,因为它在JSpinner中说有一个错误,因为文本不是
Double

public class SpinnerSpecialModel
        extends AbstractSpinnerModel implements SpinnerMinMaxModel {

  public static final double DEFAULT_MINIMUM = 0.0;
  public static final double DEFAULT_MAXIMUM = Double.POSITIVE_INFINITY;
  public static final double DEFAULT_STEP = 1.0;
  public static final double DEFAULT_VALUE = 1.0;
  public static final double DEFAULT_SPECIAL_NUMBER = -1.0;
  public static final String DEFAULT_SPECIAL_TEXT = "Auto";

  private double maximum;
  private double minimum;
  private double stepSize;
  private double currentNumber;
  private double specialNumber;
  private String specialText;

  private Object m_Value;

  public SpinnerSpecialModel(double max, double min, double step, double num, 
        double specialNum, String specialTxt) {
    maximum = max;
    minimum = min;
    stepSize = step;
    currentNumber = num;
    specialNumber = specialNum;
    specialText = specialTxt;
    setAccurateValue(num);
  }

  public SpinnerSpecialModel(double specialNum, String specialTxt) {
    this(DEFAULT_MAXIMUM, DEFAULT_MINIMUM,
        DEFAULT_STEP, DEFAULT_VALUE, specialNum, specialTxt);
  }

  public SpinnerSpecialModel() {
    this(DEFAULT_SPECIAL_NUMBER, DEFAULT_SPECIAL_TEXT);
  }

  @Override
  public Object getValue() {
    if (currentNumber == specialNumber) {
      m_Value = specialText;
    }
    else {
      m_Value = currentNumber;
    }
    return m_Value;
  }

  @Override
  public void setValue(Object value) {
    setAccurateValue(value);
  }

  private void setAccurateValue(Object value) {
    if (value instanceof Double) {
      double doubleValue = (Double) value;
      if (doubleValue != currentNumber) {
        if (doubleValue == specialNumber) {
          currentNumber = specialNumber;
          m_Value = specialText;
        }
        else if (doubleValue > maximum) {
          currentNumber = maximum;
          m_Value = maximum;
        }
        else if (doubleValue < minimum) {
          currentNumber = maximum;
          m_Value = minimum;
        }
        else {
          currentNumber = doubleValue;
          m_Value = doubleValue;
        }
        fireStateChanged();
      }
    }

    if (value instanceof String) {
      String stringValue = (String) value;
      if (stringValue.equals(specialText)) {
        this.currentNumber = specialNumber;
        this.m_Value = specialText;
        fireStateChanged();
      }
    }
  }

  @Override
  public Object getNextValue() {
    return getNewValue(+1);
  }

  @Override
  public Object getPreviousValue() {
    return getNewValue(-1);
  }

  /**
   * 
   * @param direction
   * @return 
   */
  private Object getNewValue(int direction) {
    double newValue = currentNumber + direction * stepSize;
    setAccurateValue(newValue);
    return m_Value;
  }

  @Override
  public double getMaximum() {
    return maximum;
  }

  @Override
  public double getMinimum() {
    return minimum;
  }

  @Override
  public double getStepSize() {
    return stepSize;
  }

  @Override
  public void setMaximum(double max) {
    maximum = max;
  }

  @Override
  public void setMinimum(double min) {
    minimum = min;
  }

  @Override
  public void setStepSize(double step) {
    stepSize = step;
  }
}
公共类喷丝头特殊模型
扩展AbstractSpinnerModel实现SpinnerMinMaxModel{
公共静态最终双默认值_最小值=0.0;
公共静态最终双默认值_最大值=double.POSITIVE_无穷大;
公共静态最终双默认_步=1.0;
公共静态最终双默认值=1.0;
公共静态最终双默认值\u特殊\u编号=-1.0;
公共静态最终字符串DEFAULT\u SPECIAL\u TEXT=“Auto”;
私人双倍最大值;
私人双最小值;
私人双步长;
私人双流号码;
私人双专用号码;
专用字符串specialText;
私有对象m_值;
公共喷丝头特殊模型(双最大、双最小、双步骤、双数值、,
双特殊数,字符串特殊数){
最大值=最大值;
最小值=最小值;
步长=步长;
currentNumber=num;
特殊编号=特殊编号;
specialText=specialText;
setAccurateValue(num);
}
公共喷丝头专用模型(双专用、串专用){
这(默认最大值、默认最小值、,
默认步骤、默认值、特殊值、特殊文本);
}
公共喷丝头专用模型(){
这(默认特殊编号、默认特殊文本);
}
@凌驾
公共对象getValue(){
如果(currentNumber==specialNumber){
m_值=特殊文本;
}
否则{
m_值=当前编号;
}
返回m_值;
}
@凌驾
公共无效设置值(对象值){
setAccurateValue(值);
}
私有void setAccurateValue(对象值){
如果(值实例为双精度){
double doubleValue=(double)值;
if(doubleValue!=currentNumber){
if(doubleValue==specialNumber){
currentNumber=特殊编号;
m_值=特殊文本;
}
否则如果(双值>最大值){
currentNumber=最大值;
m_值=最大值;
}
否则如果(双值<最小值){
currentNumber=最大值;
m_值=最小值;
}
否则{
currentNumber=doubleValue;
m_值=双值;
}
fireStateChanged();
}
}
if(字符串的值实例){
字符串stringValue=(字符串)值;
if(stringValue.equals(specialText)){
this.currentNumber=特殊编号;
此.m_值=specialText;
fireStateChanged();
}
}
}
@凌驾
公共对象getNextValue(){
返回getNewValue(+1);
}
@凌驾
公共对象getPreviousValue(){
返回getNewValue(-1);
}
/**
* 
*@param方向
*@返回
*/
私有对象getNewValue(int方向){
双新值=当前编号+方向*步长;
setAccurateValue(新值);
返回m_值;
}
@凌驾
公共双getMaximum(){
返回最大值;
}
@凌驾
公共双getMinimum(){
返回最小值;
}
@凌驾
公共双getStepSize(){
返回步长;
}
@凌驾
公共无效设置最大值(双倍最大值){
最大值=最大值;
}
@凌驾
公共无效设置最小值(双最小值){
最小值=最小值;
}
@凌驾
公共无效设置步长(双步长){
步长=步长;
}
}

我认为您可以通过实现自己的并将其作为参数提供给
JSpinner
构造函数来实现这一点。

实现这一点的最佳正确方法并不像编写模型那么简单,但也不是很复杂。实际上,您需要编写一个
编辑器
和一个
格式化程序
,才能拥有一个真正的MVC微调器:

  • 扩展
    JSpinner
    SpecialValuesSpinner
    的类
  • 实现SpinnerModel的类:
    SpecialValuesSpinnerModel
  • 扩展
    DefaultEditor
    并实现
    DocumentListener
    SpecialValuesPinnerEditor
  • 扩展
    NumberFormatter
    SpecialValuesSpinPerformatter
我不会向您展示所有类的代码,但以下是您在每个类中必须执行的基本操作:

特殊价值提供者:

public class SpecialValuesSpinner() extends SpinnerNumberModel {
    // in your constructor do this
    setModel(new SpecialValuesSpinnerModel(YOUR_SPECIAL_VALUES);
    setEditor(new SpecialValuesSpinnerEditor());
}
特殊值PinnerModel:

public class SpinnerSpecialValuesModel() extends JSpinner {
    // in this class you handle the fact that now, you have an
    // interval of values and a list of special values that are allowed.
    // here is what I did :
    @Override
    public Object getNextValue() {
        return incrValue(+1);
    }

    @Override
    public Object getPreviousValue() {
        return incrValue(-1);
    }

    private Object incrValue(int dir) {
        // NB : BigDecimal here because this is what I used,
        // but use what you want in your model
        BigDecimal result = null;
        BigDecimal numberBD = new BigDecimal(getNumber().toString());
        BigDecimal stepSizeBD = new BigDecimal(getStepSize().toString());
        BigDecimal dirBD = new BigDecimal(dir);
        BigDecimal nextValue = numberBD.add(stepSizeBD.multiply(dirBD));

        TreeSet<BigDecimal> currentAllowedValues = new TreeSet<BigDecimal>();
        currentAllowedValues.addAll(m_SpecialValues);
        if (getMaximum() != null) {
          currentAllowedValues.add((BigDecimal) getMaximum());
        }
        if (getMinimum() != null) {
          currentAllowedValues.add((BigDecimal) getMinimum());
        }
        if (isIncludedInBounds(nextValue)) {
          currentAllowedValues.add(nextValue);
        }

        if (dir > 0) {
          try {
            result = currentAllowedValues.higher(numberBD);
          }
          catch (NoSuchElementException e) {}
        }
        else if (dir < 0) {
          try {
            result = currentAllowedValues.lower(numberBD);
          }
          catch (NoSuchElementException e) {}
        }
        return result;
    }
}
现在,最重要的是格式化程序,它在用户输入(字符串)和数字之间进行转换,并处理模型的显示:

public class SpecialValuesSpinnerFormatter extends NumberFormatter {
    // Just override the methos StringToValue and ValueToString.
    // You can check here if the value is special
    // i.e you must display its special text instead. e.g. : "Auto" instead of -1
}

请阅读。好问题-或者换句话说:没有容易得到的解决方案:-)SpinnerModel没有不在模型中的概念(如f.i.ComboBoxModel),因此您可能需要一个自定义扩展模型和一个可以接受特殊值的自定义编辑器。@mre如果您只是告诉我阅读Oracle文档,请不要回答。如果我在这里问,那是因为我看不懂怎么做,阿文在读了一些之后documentation@Pigrou,态度轻松。我怎么知道你已经看过文件了?大多数用户都不知道这些教程,所以我想我会尝试为您指引正确的方向。我没有提供答案,只是一个评论。这是一个合适的选择。在这里,投反对票。我们应该在这个网站上互相帮助。。。谢谢你的否决票…你有没有关于无边界JSpinner的例子或想法(例如,不像Oracle文档演示中的几个月)?我认为扩展是一个不错的选择;您的子类应该跟踪
currentvalu
public class SpecialValuesSpinnerFormatter extends NumberFormatter {
    // Just override the methos StringToValue and ValueToString.
    // You can check here if the value is special
    // i.e you must display its special text instead. e.g. : "Auto" instead of -1
}