4

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

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

如何替换普通 Jspinner :我们可以看到JSpinner 在哪里我们可以看到

这是我写的模型,但似乎还不够,因为它在 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;
  }
}
4

2 回答 2

1

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

于 2013-03-28T14:22:20.657 回答
1

做到这一点的最好和正确的方法并不像仅仅写一个模型那么简单,但也不是很复杂。您实际上需要编写 anEditor和 aFormatter才能拥有真正的 MVC 微调器:

  • 一个扩展类JSpinnerSpecialValuesSpinner
  • 一个实现 SpinnerModel 的类:SpecialValuesSpinnerModel
  • 扩展DefaultEditor和实现的类DocumentListenerSpecialValuesSpinnerEditor
  • 扩展的类NumberFormatterSpecialValuesSpinnerFormatter

我不会向您展示所有类的代码,但这里基本上是您必须在每个类中执行的操作:

特殊值微调器:

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
}
于 2013-06-13T15:17:05.043 回答