自定义 JSpinner 模型不起作用

Custom JSpinner Model not working

我试图实现自己的 JSpinner 模型来接受 enumeration(包括 I18N),所以我这样做了:

searchSpinner.setModel(new AbstractSpinnerModel() {

    int index = 0;
    int minIndex = 0;
    int maxIndex = MY_ENUM.values().length - 1;
    Object selected = MY_ENUM.values()[index];

    @Override
    public Object getValue() {
        return selected;
    }

    @Override
    public void setValue(Object value) {
        selected = value;
        fireStateChanged();
    }

    @Override
    public Object getNextValue() {
        if (index < maxIndex) {
            index++;
        }
        fireStateChanged();
        return MY_ENUM.values()[index];
    }

    @Override
    public Object getPreviousValue() {
        if (index > minIndex) {
            index--;
        }
        fireStateChanged();
        return MY_ENUM.values()[index];
    }

    @Override
    public void addChangeListener(ChangeListener l) {

    }

    @Override
    public void removeChangeListener(ChangeListener l) {

    }
});

问题是它不起作用,甚至微调列表看起来 已禁用。我做错了什么?

更新:基于第一个答案

您应该从 AbstractSpinnerModel 扩展(请注意他的问题的新手——注意他的原始问题有 class 实现 SpinnerModel 接口。他后来更改了他的代码以反映我的建议) 并确保在适当的时候调用 fireStateChanged() 方法。此外,您还没有考虑边缘情况和超出边缘情况。

例如,

import javax.swing.*;
import javax.swing.JSpinner.DefaultEditor;

public class MySpinnerPanel extends JPanel {
   public static void main(String[] args) {
      JSpinner spinner = new JSpinner(new MyEnumSpinnerModel());
      JSpinner.DefaultEditor editor = (DefaultEditor) spinner.getEditor();
      editor.getTextField().setColumns(5);

      JPanel panel = new JPanel();
      panel.add(spinner);
      JOptionPane.showMessageDialog(null, panel);
   }
}

enum MyEnum {
   FE, FI, FO, FUM, FOO, FUBAR, SPAM
}

class MyEnumSpinnerModel extends AbstractSpinnerModel {
   private int index = 0;

   @Override
   public Object getValue() {
      return MyEnum.values()[index];
   }

   @Override
   public void setValue(Object value) {
      if (value instanceof MyEnum) {
         index = ((MyEnum) value).ordinal();
         fireStateChanged();
      } else {
         String text = value.toString() + " is not a valid enum item";
         throw new IllegalArgumentException(text);
      }
   }

   @Override
   public Object getNextValue() {
      if (index >= MyEnum.values().length - 1) {
         return null;
      } else {
         return MyEnum.values()[index + 1];
      }
   }

   @Override
   public Object getPreviousValue() {
      if (index <= 0) {
         return null;
      } else {
         return MyEnum.values()[index - 1 ];
      }
   }
}

编辑

请注意,模型本身不应要求侦听器通知视图(根据此问题的其他答案),因为这是 AbstractSpinnerModel 内部所做的。它的 fireStateChange() 方法是模型本身应调用以触发此通知的方法,与 Swing 中的大多数其他类似模型结构相同,例如您创建的派生自 AbstractTableModel 的任何 TableModel 对象。有关详细信息,请参阅 SpinnerListModel 的源代码。您的代码应模拟此 class.

您应该使用 ChangeListener 通知视图模型中的更改。

spinner = new JSpinner(new SpinnerModel() {
    private ChangeListener l;

    @Override
    public void setValue(Object value) {
        ...

        if(l != null) {
            l.stateChanged(new ChangeEvent(this));
        }
    }

    ...

    @Override
    public void addChangeListener(ChangeListener l) {
        this.l = l;
    }

    @Override
    public void removeChangeListener(ChangeListener l) {
        if(this.l == l) {
            this.l = null;
        }
    }
});

编辑:可以使用List注册多个监听器