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