こんにちは。「Javaを復習する初心者」です。
SwingでJSpinner、JSliderを扱ってみました。
JSpinner、JSliderはユーザに連続した値から選択してもらうときに使います。JSpinnerは値と値の上下ボタンが表示されます。JSliderではスライダーが表示されます。つまみをスライドすることで値を選択できます。
以下のプログラムを雛形として使います。
import javax.swing.JFrame;
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(350, 250);
init();
setVisible(true);
}
private void init() {
// 設置処理
}
}
JSpinner
JSpinnerとSpinnerModel
JSpinnerでは以下のコンストラクタが用意されています。
- JSpinner()
- JSpinner(SpinnerModel model)
2つ目のコンストラクタでは引数がSpinnerModelインターフェースの実装クラスです。このインターフェースが値の範囲、初期値を管理しているようです。1つ目のコンストラクタでは引数がありませんが、内部的にはSpinnerModelインターフェースの実装クラスであるSpinnerNumberModelのインスタンスが、初期値が0で最小値または最大値の制限なしで作成されます。2つ目のコンストラクタでは引数にSpinnerNumberModelクラスのインスタンスを指定するのが一般的のようです。いくつかコンストラクタがあるのですが、ここでは以下を使ってみます。
- SpinnerNumberModel(int value, int minimum, int maximum, int stepSize)
実際に、以下のように使ってみました。
private void init() {
// 設置処理
setLayout(new FlowLayout());
JSpinner spinner1 = new JSpinner();
add(spinner1);
JSpinner spinner2 = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1));
add(spinner2);
JSpinner spinner3 = new JSpinner(new SpinnerNumberModel(0, -10000, 10, 1));
add(spinner3);
}
レイアウトマネージャをFlowLayoutにして、設置してみたのですが、横幅が最小値と最大値から決定されるようです。spinner1は値の制限はないのですが、表示される桁数が一桁になってしまってます。なのでSpinnerNumberModelのインスタンスを使って明示的に最小値・最大値を決めた方が良いかもしれません。ただし、レイアウトマネージャがBorderLayoutの場合は自動的に横幅を広げてくれます。
ChangeListener
addChangeListenerメソッドでリスナーを追加することができます。値が変更されるたびに通知されます。引数はChangeListenerインターフェースの実装クラスです。このインターフェースはstateChangedメソッドのみ持ちます。
以下、実装例です。
private void init() {
// 設置処理
setLayout(new FlowLayout());
JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1));
add(spinner);
spinner.addChangeListener(event -> {
System.out.println("現在の値:" + spinner.getValue());
});
}
初期状態から上ボタンをクリックすると、コンソールに「現在の値:1」と表示されます。
JSlider
コンストラクタとBoundedRangeModel
JSliderでは内部的にはBoundedRangeModelインターフェースのが値の範囲を扱っているようです。コンストラクタJSlider(BoundedRangeModel brm)があります。他にもBoundedRangeModelを意識することなく使えるコンストラクタが用意されてます。以下を使ってみました。
- JSlider()
- JSlider(int min, int max, int value)
これ以外にもコンストラクタが用意されてますが、今回は使いませんでした。また、使用されるBoundedRangeModelインターフェースの実装クラスはDefaultBoundedRangeModelのようです。
以下、3つのスライダーを設置してみました。
private void init() {
// 設置処理
setLayout(new FlowLayout());
JSlider slider1 = new JSlider();
add(slider1);
JSlider slider2 = new JSlider(0, 10, 2);
add(slider2);
JSlider slider3 = new JSlider(-1000, 0, -100);
add(slider3);
}
JSlider()では範囲が0から100、初期値が50の水平スライダを作成します。JSlider(int min, int max, int value)では最小値、最大値、および初期値を指定して、水平スライダを作成します。指定できる数値は負の数も扱えます。数値の組み合わせに矛盾があるとIllegalArgumentExceptionが発生します。例えば、「new JSlider(0, 10, -2)」はエラーです。
addChangeListenerとJLabel
スライダーの値を表示する場合はJLabelを生成して、スライダーの値を設定する等の方法があります。スライダーの値が変更されたときのリスナーはaddChangeListenerで設定することができます。
以下では、スライダーの値が変更されたときに、JLabelに値を出力しています。
private void init() {
// 設置処理
setLayout(new FlowLayout());
JSlider slider = new JSlider();
add(slider);
JLabel label = new JLabel(String.valueOf(slider.getValue()));
add(label);
slider.addChangeListener(event -> {
label.setText(String.valueOf(slider.getValue()));
});
}
マウスでスライダーのつまみをドラッグして動かすと、ラベルの表示が変わります。
目盛りとラベル
目盛りを追加することができます。以下のメソッドを使います。
- void setPaintTicks(boolean b)
- void setMinorTickSpacing(int n)
- void setMajorTickSpacing(int n)
setPaintTicksの引数をtrueにして、setMinorTickSpacing、setMajorTickSpacingで小目盛、大目盛の設定をします。setPaintTicks(true)を実行しただけでは目盛りは表示されません。
更にラベルを追加したい場合、setPaintLabels(true)を実行します。初期設定ではラベルは大目盛に合わせて表示されます。ラベルを指定する場合、void setLabelTable(Dictionary labels)メソッドを使います。Dictionaryクラスは抽象メソッドを含むため、実際にはそのサブクラスであるHashtableを使います。ここで、キーと値の組み合わせはIntegerとjava.swing.JComponentです。
以下、設定例です。
private void init() {
// 設置処理
setLayout(new FlowLayout());
JSlider slider1 = new JSlider();
add(slider1);
slider1.setPaintTicks(true);
slider1.setMinorTickSpacing(10);
slider1.setMajorTickSpacing(20);
JSlider slider2 = new JSlider();
add(slider2);
slider2.setPaintTicks(true);
slider2.setMinorTickSpacing(10);
slider2.setMajorTickSpacing(20);
slider2.setPaintLabels(true);
JSlider slider3 = new JSlider();
add(slider3);
slider3.setPaintTicks(true);
slider3.setMinorTickSpacing(10);
slider3.setMajorTickSpacing(20);
Dictionary<Integer, JComponent> dictionary = new Hashtable<>();
dictionary.put(new Integer(0), new JLabel("min"));
dictionary.put(new Integer(50), new JLabel("middle"));
dictionary.put(new Integer(100), new JLabel("max"));
slider3.setPaintLabels(true);
slider3.setLabelTable(dictionary);
}
slider1では目盛りの設定をしています。小目盛10、大目盛20で設定しています。slider2ではさらにラベルを表示しています。初期設定なので、大目盛に合わせてラベルが表示されています。slider3では目盛り0、50、100に対してラベルを付けています。JComponentのサブクラスであるJLabelを使っています。ここではコンストラクタJLabel(String text)を使っていますが、JLabel(Icon image)を使えば画像がつけられるようです。