JSpinner:如何显示数字和文字?

时间:2013-03-28 14:17:14

标签: java swing jspinner

我想创建一个JSpinner,它可以在指定的最小值指定的最大值之间取每个可能的Double值。

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

如何替换Normal Jspinner : we can see "-1" JSpinner where we can see "Auto" instead of "-1" even if Auto equals actually -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;
  }
}

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

这样做的最佳和正确的方法并不像编写模型那么简单,但并不是很复杂。实际上你需要写一个Editor和一个Formatter来拥有一个真正的MVC微调器:

  • 扩展JSpinner的类SpecialValuesSpinner
  • 实现SpinnerModel的类:SpecialValuesSpinnerModel
  • 扩展DefaultEditor并实施DocumentListener的类:SpecialValuesSpinnerEditor
  • 扩展NumberFormatterSpecialValuesSpinnerFormatter
  • 的类

我不会向您展示所有课程的代码,但基本上您必须在每个课程中执行以下操作:

SpecialValuesSpinner:

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

SpecialValuesSpinnerModel:

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

在SpecialValuesSpinnerEditor中,我们使用Document Listener进行自动完成(很容易做到,只需搜索SO)。

public class SpecialValuesSpinnerEditor extends DefaultEditor implements DocumentListener {

    // You have to do in your contructor
    SpecialValuesSpinnerFormatter formatter = 
        new SpecialValuesSpinnerFormatter (spinner.getSpecialValues(), format);
    getTextField().setFormatterFactory(new DefaultFormatterFactory(formatter));
}

现在,最重要的是,Formatter在用户输入(字符串)和数字之间进行转换,并处理模型的显示:

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
}