こんにちは。ハンドルネーム「Javaを復習する初心者」です。このサイトはプログラミング言語Javaの復習・学習をするブログです。プログラムの開発・実行はEclipseで行ってます。
スポンサーリンク
お知らせ
  • 参考文献のページ作りました。
  • Amazon.co.jpアソシエイトに参加していますが、参考文献の紹介はもしもアフィリエイトに統一しました。
  • 2016年10月9日からは投稿ペースを落とします。週1回くらいにする予定です。
スポンサーリンク

SwingのJSpinner、JSlider

こんにちは。「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)を使えば画像がつけられるようです。