時間をセンチ秒単位で入力するための使いやすい方法が必要です。数字を入力すると、数字が右から押し込まれ、自動的に先行ゼロ「.」が追加されます。および必要に応じて ":" を使用します。たとえば、次のようになります。
"" => "0.03" => "0.31" => "3.14" => "31.41" => "3:14.15"
また、「f」を入力すると、「DNF」(「終了しませんでした」) となるはずです: 「3:14.15」 => 「DNF」 => 「0.04」
以下の私のコードは「機能」しますが、常にカーソルが最後に置かれることを除いて (完全に置換されるため)、誰かが途中で編集しようとするとうまくいきません。カーソルをあるべき場所に保つ簡単な方法はありますか? さらに重要なことは、私のアプローチ全体が適切であるか、それとも本当に別の方法で行う必要があるかということです。私は以前に多くの方法 (JFormattedTextField と Formatters、DocumentFilter、DocumentListener など) を試しましたが、ここで同様のことを提案されていたため、それらを機能させることができませんでした。
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
class TimeField extends JTextField {
public static void main ( String[] args ) {
JFrame frame = new JFrame();
frame.add( new TimeField() );
frame.add( new TimeField(), BorderLayout.SOUTH );
frame.pack();
frame.setDefaultCloseOperation( frame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
TimeField () {
super( 10 );
setHorizontalAlignment( RIGHT );
setFont( new Font( "MONOSPACED", Font.BOLD, 32 ));
((AbstractDocument) getDocument()).setDocumentFilter( new DocumentFilter() {
public void insertString ( DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr ) throws BadLocationException {
replace( fb, offset, 0, string, attr );
}
public void remove ( DocumentFilter.FilterBypass fb, int offset, int length ) throws BadLocationException {
replace( fb, offset, length, "", null );
}
public void replace ( DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attrs ) throws BadLocationException {
fb.replace( offset,length, text, attrs );
if ( text.contains("f") ) {
fb.replace( 0, getText().length(), "DNF", null );
return;
}
text = getText(); // get current text
text = text.replaceAll( "\\D", "" ); // remove non-digits
text = text.replaceAll( "^0+", "" ); // remove leading zeros
while ( text.length() < 3 ) text = "0" + text; // make at least three digits
text = text.replaceAll( "(.)(..)$", "$1.$2" ); // add point if necessary
text = text.replaceAll( "(.)(..\\.)", "$1:$2" ); // add colon if necessary
fb.replace( 0, getText().length(), text, null ); // replace original with formatted
}
} );
}
}
編集:以前に JFormattedTextField を試しましたが、これが私の最善の試みです。数字を入力できます。フォーカスがフィールドを離れると、valueToString が呼び出され、ポイント + コロンが追加されて表示されます。しかし、これは編集後ではなく、編集中に実行したいと思います。MaskFormatter が明らかにそれを行うことができるので、私は何かが欠けているに違いありません。
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
class TimeField extends JFormattedTextField {
public static void main(String[] args) {
//Create Event Disptach Thread for swing UI and its components to run on
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
JFormattedTextField ftf = new JFormattedTextField(new TimeFormatter());
ftf.setHorizontalAlignment(JTextField.RIGHT);
ftf.setFont(new Font(Font.MONOSPACED, Font.BOLD, 32));
ftf.setColumns(10);
frame.getContentPane().add(ftf);
frame.getContentPane().add(new JButton("foo"), BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
static class TimeFormatter extends DefaultFormatter {
public Object stringToValue(String text) {
System.out.println("stringToValue(" + text + ")");
return text == null ? "" : text.replaceAll("\\D", "");
}
public String valueToString(Object value) {
System.out.println("valueToString(" + value + ")");
return value == null ? null : format((String)value);
}
private String format(String text) {
text = text.replaceAll("\\D", ""); // remove non-digits
text = text.replaceAll("^0+", ""); // remove leading zeros
while (text.length() < 3) text = "0" + text; // make at least three digits
text = text.replaceAll("(.)(..)$", "$1.$2"); // add point
text = text.replaceAll("(.)(..\\.)", "$1:$2"); // add colon if necessary
return text;
}
}
}