Java Swingで,値検査(年月日)とフル桁遷移を実現する

業務でJava Swingを利用することになったんですが・・・.しらねえ. 基本的なことはググれば分かるんですが,タイトルのネタ二つがよくわからなかったので,調べてみた

1.値検査(年月日)

一言でいうと,JFormattedTextFieldっていうコンポーネントを使い,そのコンポーネントにDocumentListener()っていうリスナーを刺せばOK. JFormattedTextFieldは,引数として渡されたフォーマット形式(SimpleDateFormatとか)どおりに,書式を整えてくれるもの. DocumentLisnerは,テキストフィールドの変化(入力・削除など)に対するリスナー.

以下,具体的なコード.オリジナルのコードから,必要な部分を切り取っただけなので,動かないかも.

public class HavingDataChecker extends JFrame{
    private JFormattedTextField text1;

    public static void main(String[] args) {
        HavingDataChecker frame = new HavingDataChecker();

        //set close event
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //set window title
        frame.setTitle("JFormattedTextField Sample");

        //set frame coordinaiton
        frame.setBounds(100,200,450,250);

        //visible frame
        frame.setVisible(true);
    }

    public HavingDataChecker() {
        JPanel panelBase = new JPanel();

        //define format
        SimpleDateFormat nf1 = new SimpleDateFormat("MM");

        //create textfield
        text1 = new JFormattedTextField(nf1);

        //add listener to textfield
        text1.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void removeUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }

            @Override
            public void insertUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                // TODO 自動生成されたメソッド・スタブ
                checkMonth(text1);
            }
        });

        //set item size
        text1.setPreferredSize(new Dimension(180,20));

        //add textfield to panel
        panelBase.add(text1);

        //add panel
        getContentPane().add(panelBase);

    }

    private void checkMonth(JTextField from) {
        Runnable docheck = new Runnable() {
            @Override
            public void run() {
                // TODO 自動生成されたメソッド・スタブ
                String insertedString = from.getText();
                if(!(insertedString.equals(""))) {
                    int value = Integer.parseInt(insertedString);
                    if(value > 12) {
                        from.setText("");
                    }
                }
            }
        };
        SwingUtilities.invokeLater(docheck);
    }
}

重要なのはこの辺

1-1. JFormattedTextField作成部分

//define format
SimpleDateFormat nf1 = new SimpleDateFormat("MM月");

//create textfield
text1 = new JFormattedTextField(nf1);

上の方で,書式(この場合は,年月日の「月」部分)を指定している. 下の部分で,JFormattedTextFieldを作成する.

1-2. 値検査

DocumentListenerの刺し方はこんな感じ.

//add listener to textfield
text1.getDocument().addDocumentListener(new DocumentListener() {

    @Override
    public void removeUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        // TODO 自動生成されたメソッド・スタブ
        checkMonth(text1);
            }
});

今回は,「月」の型検査をやりたい.なので,「13」以上の値が入力されたら,空文字に置換する. ただ,EDTの関係があるので,処理はRunnableインタフェースを実装しなければいけない.

private void checkMonth(JTextField from) {
    Runnable docheck = new Runnable() {
        @Override
        public void run() {
            // TODO 自動生成されたメソッド・スタブ
            String insertedString = from.getText();
            if(!(insertedString.equals(""))) {
                int value = Integer.parseInt(insertedString);
                if(value > 12) {
                    from.setText("");
                }
            }
        }
    };
    SwingUtilities.invokeLater(docheck);

}

(「0月」を許容しているのはご愛嬌・・・.サンプルコードだから・・・)

2.フル桁遷移

年月日の「年」を入れたら,「月」のテキストフィールドに自動的に移動するやつのこと. 実装方法は, めっちゃ簡単.JTextField.getCaretPosition() っていうのを使えば,「現在のカーソル位置」を取得できる.何らかのリスナーを実行した後に,この値を取得すればいい. 移動先のテキストフィールドの指定は,JTextField.requestFocus()でOK. 私は,こんなコードにまとめた.遷移元と遷移先を指定する感じ.

private void goNext(JTextField from, JTextField to) {
    if(from.getCaretPosition() == 1) {to.requestFocus();};
}

とりあえず,こんな感じでおわり.

3. 既知の問題点

所定の値以外が入力された後の値がへん

例えば「13」っていれると,強制的に「12」が入る. 空文字を入れたはずなのに・・・

SimpleDateFormat("MM") をSimpleDateFormat("DD")に変えた後に, 「31」とかを入力すると, 「31」が入力されるので,SimpleDateFormatまたはJFormattedTextField側の問題だと推測している. 調べなきゃ・・・.

例外処理をしていないので「あああ」とかを入れると,実行時エラーが出る

NumberFormatException(?)が出ます.まじめに制御すればいいので,致命傷ではない(と思っている). いつか,解決版に更新するかも.