我想创建一个JSpinner,它可以在指定的最小值和指定的最大值之间获取每个可能的Double值.
此外,JSpinner应该能够显示文本而不是特定值.假设我们的JSpinner可以取-1到10之间的值.我想显示一个文本,例如“自动”,而不是-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;
}
}
最佳答案 这样做的最佳和正确的方法并不像编写模型那么简单,但并不是很复杂.您实际上需要编写一个Editor和一个Formatter来拥有一个真正的MVC微调器:
>扩展JSpinner的类:SpecialValuesSpinner.
>实现SpinnerModel的类:SpecialValuesSpinnerModel
>扩展DefaultEditor并实现DocumentListener的类:SpecialValuesSpinnerEditor
>扩展NumberFormatter的类:SpecialValuesSpinnerFormatter
我不打算向您展示所有课程的代码,但这里基本上是您必须要做的每一个:
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
}