自定义 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注册多个监听器
我试图实现自己的 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注册多个监听器