スピナ2つではコードが限定的(Aで無ければBと決まる状態)になるので, 3つに増やしました.
また、残りステータス値が分かりやすいようにスピナ群の上に表示を付けました.
各ステータス値が 10 (合計30) からレベルアップして合計40まで設定できるようになったという状況です.
各ステータスの変化を全てのスピナに反映する必要があるため, 全体を管理するクラス (StatusSpinnerNumberModelManager) を作りまして, 内部でモデルの通知を受け取り, 全モデルの最大値を変更しています.
このような動作を考えられていると思いましたが, 合っているでしょうか.
java
1import java.awt.BorderLayout;
2import java.util.HashSet;
3import java.util.Set;
4
5import javax.swing.BoxLayout;
6import javax.swing.JFrame;
7import javax.swing.JPanel;
8import javax.swing.JSpinner;
9import javax.swing.JTextField;
10import javax.swing.SpinnerNumberModel;
11import javax.swing.event.ChangeListener;
12
13public class Test extends JFrame {
14
15
16 static class StatusSpinnerNumberModelManager {
17
18 interface ChangeStatusListener {
19 void onChangeStatus(StatusSpinnerNumberModelManager source);
20 }
21 private ChangeStatusListener listener;
22
23 private int new_status_total;
24
25 private Set<SpinnerNumberModel> modelSet = new HashSet<>();
26
27 private int leftStatus;
28
29 private ChangeListener changeListener = e->changeMaximum();
30
31
32 StatusSpinnerNumberModelManager(int new_status_total) {
33 this.new_status_total = new_status_total;
34 }
35
36 void add(SpinnerNumberModel model) {
37 if(modelSet.contains(model)) return; //二重登録防止
38 modelSet.add(model);
39 model.setMinimum(new Integer(model.getNumber().intValue())); //現在値を最小値とします.
40 model.addChangeListener(changeListener); //リスナを登録します.
41 changeMaximum();
42 }
43 int getLeftStatus() { return leftStatus; }
44 void setChangeStatusListener(ChangeStatusListener listener) {
45 this.listener = listener;
46 }
47
48 private int getTotal() {
49 int total = 0;
50 for(SpinnerNumberModel model : modelSet) { total += model.getNumber().intValue(); }
51 return total;
52 }
53 56
57 private void changeMaximum() {
58 leftStatus = new_status_total - getTotal(); //現在値から幾つまで設定できるか.
59 for(SpinnerNumberModel model : modelSet) {
60 model.removeChangeListener(changeListener); //setMaximumでChangeEventが発火するのを防ぐ
61 model.setMaximum(model.getNumber().intValue() + leftStatus); //最大値を変更
62 model.addChangeListener(changeListener); //リスナを戻す
63 }
64 if(listener != null) listener.onChangeStatus(this);
65 }
66 };
67
68 public Test() {
69 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
70 this.setTitle("test");
71 this.setSize(650, 420);
72
73 //レベルアップでステータスが(現在合計30から)合計40まで設定できるようになった!(と仮定)
74 int new_status_total = 40;
75
76 StatusSpinnerNumberModelManager statusModelManager = new StatusSpinnerNumberModelManager(new_status_total);
77
78 //残りステータス値
79 JTextField textfield = new JTextField();
80 textfield.setEditable(false);
81 getContentPane().add(textfield, BorderLayout.NORTH);
82 statusModelManager.setChangeStatusListener(source->textfield.setText(""+source.getLeftStatus()));
83
84 JPanel panel = new JPanel(null);
85 panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
86 getContentPane().add(panel, BorderLayout.CENTER);
87
88 //can plus 10 totally
89 JSpinner spinner1 = new JSpinner();
90 SpinnerNumberModel model1 = new SpinnerNumberModel(10, null, null, 1);
91 spinner1.setModel(model1);
92 panel.add(spinner1);
93 statusModelManager.add(model1);
94
95 JSpinner spinner2 = new JSpinner();
96 SpinnerNumberModel model2 = new SpinnerNumberModel(10, null, null, 1);
97 spinner2.setModel(model2);
98 panel.add(spinner2);
99 statusModelManager.add(model2);
100
101 JSpinner spinner3 = new JSpinner();
102 SpinnerNumberModel model3 = new SpinnerNumberModel(10, null, null, 1);
103 spinner3.setModel(model3);
104 panel.add(spinner3);
105 statusModelManager.add(model3);
106 }
107
108 public static void main(String[] args) {
109 Test test = new Test();
110 test.setVisible(true);
111 }
112}