2012-08-09 78 views
5

在我的一個java應用程序中,有一個字段,用戶應該輸入一個時間。我知道,我可以簡單地保持它作爲一個正常的JTextField,並在驗證的時候,我可以檢查值等等...限制用戶在JTextField中輸入時間的最佳方法

但我認爲有比這更好的方式..

對於例如,如果這是一個日期的事情,那麼JXDatePicker(它與swingx一起)可以非常方便地使用。最終,用戶選擇保證是一個日期。

同樣,時間選擇也必須有更好的方法。如果你知道更好的解決方案,有人會分享你的知識嗎?

任何想法是讚賞。謝謝!

回答

13

你可以使用一個JFormattedTextField看看下面的例子,這將創建一個JFormattedTextField它將只接受數字,並把它們放在表格XXhXXminXXs然後添加一個ActionListenerJFormattedTextField並在試圖解析爲一個有效的時間對象時ENTER現在我只顯示使用JFormattedTextFieldActionListener的我沒有嘗試轉換或任何轉換和分析的有效時間:

enter image description here

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.text.ParseException; 
import javax.swing.JFormattedTextField; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.text.MaskFormatter; 

public class FormattedTextFieldExample { 

    public FormattedTextFieldExample() { 
     initComponents(); 
    } 

    private void initComponents() { 
     JFrame frame = new JFrame("JFormattedTextField Example"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     MaskFormatter mask = null; 
     try { 
      mask = new MaskFormatter("##h##min##s");//the # is for numeric values 
      mask.setPlaceholderCharacter('#'); 
     } catch (ParseException e) { 
      e.printStackTrace(); 
     } 

     // 
     // Create a formatted text field that accept a valid time. 
     // 
     final JFormattedTextField timeField = new JFormattedTextField(mask); 

     //Add ActionListener for when enter is pressed 
     timeField.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       Object source = ae.getSource(); 
       if (source == timeField) { 
        //parse to a valid time here 
        System.out.println(timeField.getText()); 
       } 
      } 
     }); 

     frame.add(timeField); 

     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new FormattedTextFieldExample(); 
      } 
     }); 
    } 
} 
+2

謝謝@DavidKroukamp,這是一個非常好的。我會試試這個並給我反饋。之前不知道「JFormattedTextField」。非常感謝!! – Anubis 2012-08-09 10:42:34

+0

不要讓David的優秀答案崩潰,但沒有驗證值,但這要歸結爲個人需求;) – MadProgrammer 2014-08-25 01:46:51

7
  • 多個JSpinner實例允許選擇小時,分鐘和秒
  • 使用JFormattedTextField一些改進,以提供即時的用戶反饋(例如着色背景儘快紅色作爲輸入無效)
6

我做了一個原型TimeField的前一段時間,它仍然需要一點的工作,但這個概念是非常基本的。

它基本上呈現了兩個JTextFields,一個用於一小時,一個用於分鐘,並使它們看起來是單個字段。

通過使用一些DocumentFilter s,它限制了用戶的輸入。

enter image description here

我這樣做是前一段時間,它需要的工作,但其基本思想是存在的......如果你有問題,你需要嘗試和搞清楚自己;)

/** 
* 
* @author MadProgrammer 
*/ 
public class TimeField extends javax.swing.JPanel { 

    // The time of day... 
    public enum TimeOfDay { 

    AM, 
    PM 
    } 
    private HourDocumentFilter hourDocumentFilter; 
    private MinuteDocumentFilter minDocumentFilter; 
    private HourKeyHandler hourKeyHandler; 
    private MinuteKeyHandler minuteKeyHandler; 
    private HourFocusHandler hourFocusHandler; 
    private MinuteFocusHandler minuteFocusHandler; 
    private boolean use24HourClock; 
    private ActionHandler actionHandler; 

    /** 
    * Creates new form TimeField 
    */ 
    public TimeField() { 
    initComponents(); 
    pnlFields.setBorder(new CompoundBorder(UIManager.getBorder("TextField.border"),new EmptyBorder(0, 2, 0, 2))); 

    set24HourClock(false); 
    setTime(new Date()); 
    fldHour.addKeyListener(new HourKeyHandler()); 
    } 

    @Override 
    public void addNotify() { 
    super.addNotify(); 
    // Add all the required functionality to make this thing work... 
    ((AbstractDocument) fldHour.getDocument()).setDocumentFilter(getHourDocumentFilter()); 
    ((AbstractDocument) fldMin.getDocument()).setDocumentFilter(getMinuteDocumentFilter()); 
    fldHour.addFocusListener(getHourFocusHandler()); 
    fldMin.addFocusListener(getMinuteFocusHandler()); 
    fldHour.addKeyListener(getHourKeyHandler()); 
    fldMin.addKeyListener(getMinuteKeyHandler()); 
    fldHour.addActionListener(getActionHandler()); 
    fldMin.addActionListener(getActionHandler()); 
    cmbTimeOfDay.addActionListener(getActionHandler()); 
    } 

    @Override 
    public void removeNotify() { 
    // Clean up our listeners... 
    ((AbstractDocument) fldHour.getDocument()).setDocumentFilter(null); 
    ((AbstractDocument) fldMin.getDocument()).setDocumentFilter(null); 
    fldHour.removeFocusListener(getHourFocusHandler()); 
    fldMin.removeFocusListener(getMinuteFocusHandler()); 
    fldHour.removeKeyListener(getHourKeyHandler()); 
    fldMin.removeKeyListener(getMinuteKeyHandler()); 
    fldHour.removeActionListener(getActionHandler()); 
    fldMin.removeActionListener(getActionHandler()); 
    cmbTimeOfDay.removeActionListener(getActionHandler()); 
    super.removeNotify(); 
    } 

    /** 
    * Adds an action listener to the component. Actions are fired when the user 
    * presses the enter key 
    * 
    * @param listener 
    */ 
    public void addActionListener(ActionListener listener) { 
    listenerList.add(ActionListener.class, listener); 
    } 

    public void removeActionListener(ActionListener listener) { 
    listenerList.remove(ActionListener.class, listener); 
    } 

    /** 
    * Returns the field that is acting as the hour editor 
    * 
    * @return 
    */ 
    public JTextField getHourEditor() { 
    return fldHour; 
    } 

    /** 
    * Returns the field that is acting as the minute editor 
    * 
    * @return 
    */ 
    public JTextField getMinuteEditor() { 
    return fldMin; 
    } 

    /** 
    * Returns the combo box that provides the time of day selection 
    * 
    * @return 
    */ 
    public JComboBox getTimeOfDayEditor() { 
    return cmbTimeOfDay; 
    } 

    /** 
    * Returns the internal action handler. This handler monitors actions on the 
    * individual components and merges them into one. 
    * 
    * @return 
    */ 
    protected ActionHandler getActionHandler() { 
    if (actionHandler == null) { 
     actionHandler = new ActionHandler(); 
    } 
    return actionHandler; 
    } 

    /** 
    * Returns the hour key listener 
    * 
    * @return 
    */ 
    protected HourKeyHandler getHourKeyHandler() { 
    if (hourKeyHandler == null) { 
     hourKeyHandler = new HourKeyHandler(); 
    } 
    return hourKeyHandler; 
    } 

    /** 
    * Returns the minute key listener 
    * 
    * @return 
    */ 
    protected MinuteKeyHandler getMinuteKeyHandler() { 
    if (minuteKeyHandler == null) { 
     minuteKeyHandler = new MinuteKeyHandler(); 
    } 
    return minuteKeyHandler; 
    } 

    /** 
    * Returns the document filter used to filter the hour field 
    * 
    * @return 
    */ 
    protected HourDocumentFilter getHourDocumentFilter() { 
    if (hourDocumentFilter == null) { 
     hourDocumentFilter = new HourDocumentFilter(); 
    } 
    return hourDocumentFilter; 
    } 

    /** 
    * Returns the document filter user to filter the minute field 
    * 
    * @return 
    */ 
    protected MinuteDocumentFilter getMinuteDocumentFilter() { 
    if (minDocumentFilter == null) { 
     minDocumentFilter = new MinuteDocumentFilter(); 
    } 
    return minDocumentFilter; 
    } 

    /** 
    * Returns the focus listener used to monitor the hour field 
    * 
    * @return 
    */ 
    protected HourFocusHandler getHourFocusHandler() { 
    if (hourFocusHandler == null) { 
     hourFocusHandler = new HourFocusHandler(); 
    } 
    return hourFocusHandler; 
    } 

    /** 
    * Used the focus listener used to monitor the minute field 
    * 
    * @return 
    */ 
    protected MinuteFocusHandler getMinuteFocusHandler() { 
    if (minuteFocusHandler == null) { 
     minuteFocusHandler = new MinuteFocusHandler(); 
    } 
    return minuteFocusHandler; 
    } 

    /** 
    * Sets the time based on the supplied date 
    * 
    * @param date 
    */ 
    public void setTime(Date date) { 
    Calendar cal = Calendar.getInstance(); 
    cal.setTime(date); 
    int hour = cal.get(Calendar.HOUR); 
    int min = cal.get(Calendar.MINUTE); 
    int dayPart = cal.get(Calendar.AM_PM); 

    TimeOfDay timeOfDay = TimeOfDay.AM; 
    switch (dayPart) { 
     case Calendar.PM: 
     timeOfDay = TimeOfDay.PM; 
     break; 
    } 

    setTime(hour, min, timeOfDay); 
    } 

    /** 
    * Sets the time based on a 24 hour clock. The field does not need to be in 24 
    * hour mode to use this method, the method will automatically correct the 
    * hour appropriately. 
    * 
    * @param hour 
    * @param min 
    */ 
    public void setTime(int hour, int min) { 
    hour = correctHour(hour); 
    min = correctMinute(min); 

    TimeOfDay timeOfDay = TimeOfDay.AM; 
    if (hour >= 12) { 
     timeOfDay = TimeOfDay.PM; 
    } 

    setTime(hour, min, timeOfDay); 
    } 

    /** 
    * Corrects the minute value to make sure it is within allowable ranges. 
    * 
    * For example, if you pass in 90 the method, it will automatically correct 
    * the value to 30, discard the overflow. 
    * 
    * This will not effect the hour value...although this might be worth 
    * consideration in the future 
    * 
    * @param min 
    * @return 
    */ 
    protected int correctMinute(int min) { 
    // Make sure the value is positive. 
    // If we were interested in altering the hour value as well, we wouldn't 
    // want to do this... 
    if (min < 0) { 
     min += (min * -2); 
    } 

    // Correct the minute value.... 
    if (min > 59) { 
     // How many hours fit into this value 
     float part = min/60f; 
     part = (float) (part - Math.floor(part)); // Get remainder 
     min = (int) (60 * part); // Calculate the number of minutes... 
    } 
    return min; 
    } 

    /** 
    * Basically, this method will attempt to correct the hour value and bring the 
    * it into range of a single day. 
    * 
    * We are basically going to try and figure out how many parts of the day that 
    * the hour falls in and make it equal to a single day... 
    * 
    * That is, if the hour is 35, it's actually 1.458... days, which is roughly 1 
    * day and 11 hours. We are only interested in the 11 hours, cause the date is 
    * irrelevant to us 
    * 
    * @param hour 
    * @return 
    */ 
    protected int correctHour(int hour) { 
    if (hour < 0) { 
     hour += (hour * -2); 
    } 

    if (hour > 23) { 
     float part = hour/24f; 
     part = (float) (part - Math.floor(part)); 
     hour = (int) (24 * part); 
    } 
    return hour; 
    } 

    /** 
    * Sets the time value for this field... 
    * 
    * @param hour 
    * @param min 
    * @param timeOfDay 
    */ 
    public void setTime(int hour, int min, TimeOfDay timeOfDay) { 
    hour = correctHour(hour); 
    min = correctMinute(min); 

    // Now that we have a correct hour value, we need to know if it will 
    // actually fit within the correct part of the day... 

    switch (timeOfDay) { 
     case AM: 
     cmbTimeOfDay.setSelectedIndex(0); 
     break; 
     case PM: 
     cmbTimeOfDay.setSelectedIndex(1); 
     break; 
    } 

    if (!is24HourClock()) { 
     if (hour > 12) { 
     hour -= 12; 
     } 
    } else { 
     if (hour < 12 && timeOfDay.equals(TimeOfDay.PM)) { 
     hour += 12; 
     } 
    } 

    fldHour.setText(pad(Integer.toString(hour), 2)); 
    fldMin.setText(pad(Integer.toString(min), 2)); 
    } 

    public int getHour() { 
    return Integer.parseInt(getHourEditor().getText()); 
    } 

    public int getMinute() { 
    return Integer.parseInt(getMinuteEditor().getText()); 
    } 

    public TimeOfDay getTimeOfDay() { 
    TimeOfDay tod = null; 
    switch (cmbTimeOfDay.getSelectedIndex()) { 
     case 0: 
     tod = TimeOfDay.AM; 
     break; 
     case 1: 
     tod = TimeOfDay.PM; 
     break; 
    } 
    return tod; 
    } 

    /** 
    * Sets if we should be using 24 or 12 hour clock. This basically configures 
    * the time of day field and the validation ranges of the various fields 
    * 
    * @param value 
    */ 
    public void set24HourClock(boolean value) { 
    if (value != use24HourClock) { 

     use24HourClock = value; 
     cmbTimeOfDay.setVisible(!use24HourClock); 

     if (cmbTimeOfDay.getSelectedIndex() == 1) { 
     setTime(getHour() + 12, getMinute(), getTimeOfDay()); 
     } 

     invalidate(); 
     firePropertyChange("24HourClock", !use24HourClock, value); 
    } 
    } 

    /** 
    * Returns if this is using a 24 or 12 hour clock 
    * 
    * @return 
    */ 
    public boolean is24HourClock() { 
    return use24HourClock; 
    } 

    /** 
    * This method is called from within the constructor to initialize the form. 
    * WARNING: Do NOT modify this code. The content of this method is always 
    * regenerated by the Form Editor. 
    */ 
    @SuppressWarnings("unchecked") 
    // <editor-fold defaultstate="collapsed" desc="Generated Code">       
    private void initComponents() { 
    java.awt.GridBagConstraints gridBagConstraints; 

    cmbTimeOfDay = new javax.swing.JComboBox(); 
    pnlFields = new javax.swing.JPanel(); 
    lblSeperator = new javax.swing.JLabel(); 
    fldHour = new javax.swing.JTextField(); 
    fldMin = new javax.swing.JTextField(); 

    addFocusListener(new java.awt.event.FocusAdapter() { 
     public void focusGained(java.awt.event.FocusEvent evt) { 
     doFocusGained(evt); 
     } 
    }); 
    setLayout(new java.awt.GridBagLayout()); 

    cmbTimeOfDay.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"am", "pm"})); 
    cmbTimeOfDay.setBorder(null); 
    cmbTimeOfDay.setEditor(null); 
    cmbTimeOfDay.setOpaque(false); 
    gridBagConstraints = new java.awt.GridBagConstraints(); 
    gridBagConstraints.gridx = 1; 
    gridBagConstraints.gridy = 0; 
    gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); 
    add(cmbTimeOfDay, gridBagConstraints); 

    pnlFields.setBackground(new java.awt.Color(255, 255, 255)); 
    pnlFields.setLayout(new java.awt.GridBagLayout()); 

    lblSeperator.setText(":"); 
    gridBagConstraints = new java.awt.GridBagConstraints(); 
    gridBagConstraints.gridx = 1; 
    gridBagConstraints.gridy = 0; 
    gridBagConstraints.insets = new java.awt.Insets(0, 2, 0, 2); 
    pnlFields.add(lblSeperator, gridBagConstraints); 

    fldHour.setBorder(null); 
    fldHour.setColumns(2); 
    gridBagConstraints = new java.awt.GridBagConstraints(); 
    gridBagConstraints.gridx = 0; 
    gridBagConstraints.gridy = 0; 
    pnlFields.add(fldHour, gridBagConstraints); 

    fldMin.setBorder(null); 
    fldMin.setColumns(2); 
    gridBagConstraints = new java.awt.GridBagConstraints(); 
    gridBagConstraints.gridx = 2; 
    gridBagConstraints.gridy = 0; 
    pnlFields.add(fldMin, gridBagConstraints); 

    gridBagConstraints = new java.awt.GridBagConstraints(); 
    gridBagConstraints.gridx = 0; 
    gridBagConstraints.gridy = 0; 
    add(pnlFields, gridBagConstraints); 
    }// </editor-fold>       

    private void doFocusGained(java.awt.event.FocusEvent evt) { 
    fldHour.requestFocus(); 
    } 
    // Variables declaration - do not modify      
    private javax.swing.JComboBox cmbTimeOfDay; 
    private javax.swing.JTextField fldHour; 
    private javax.swing.JTextField fldMin; 
    private javax.swing.JLabel lblSeperator; 
    private javax.swing.JPanel pnlFields; 
    // End of variables declaration     

    /** 
    * Moves the focus forward to the next field. 
    * 
    * This is used to provide "automatic" focus movement 
    */ 
    protected void moveFocusForward() { 
    if (fldHour.hasFocus()) { 
     fldMin.requestFocus(); 
    } else if (fldMin.hasFocus()) { 
     cmbTimeOfDay.requestFocus(); 
    } 
    } 

    /** 
    * Moves the focus backwards to the previous field. 
    * 
    * This is used to provide "automatic" focus movement 
    */ 
    protected void moveFocusBackward() { 
    if (fldMin.hasFocus()) { 
     fldHour.requestFocus(); 
    } else if (cmbTimeOfDay.hasFocus()) { 
     fldMin.requestFocus(); 
    } 
    } 

    /** 
    * Fires the action performed event to all registered listeners 
    * 
    * @param evt 
    */ 
    protected void fireActionPerformed(ActionEvent evt) { 
    List<ActionListener> lstListeners = Arrays.asList(listenerList.getListeners(ActionListener.class)); 
    if (!lstListeners.isEmpty()) { 
     Collections.reverse(lstListeners); 
     for (ActionListener listener : lstListeners) { 
     listener.actionPerformed(evt); 
     } 
    } 
    } 

    /** 
    * Hour key handler, used to monitor "special" keys for the hour field. 
    * 
    * This looks for the user pressing the ":" key and the right arrow key in 
    * order to perform special navigation 
    */ 
    protected class HourKeyHandler extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 
     boolean numLock = false; 
     try { 
     // Get the state of the nums lock 
     numLock = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_NUM_LOCK); 
     } catch (Exception exp) { 
     } 

     // Move focus forward if the user presses the ":" 
     if (e.getKeyCode() == KeyEvent.VK_SEMICOLON && e.isShiftDown()) { 
     moveFocusForward(); 
     // Move focus forward if the user pressed the left arrow key 
     } else if ((e.getKeyCode() == KeyEvent.VK_NUMPAD6 && !numLock) || e.getKeyCode() == KeyEvent.VK_RIGHT) { 
     // If we are in the last edit position 
     if (fldHour.getCaretPosition() >= 2) { 
      moveFocusForward(); 
      // Or we are in the first edit position and the field only contains a single character 
     } else if (fldHour.getText().trim().length() == 1 && fldHour.getCaretPosition() == 1) { 
      moveFocusForward(); 
     } 
     } 
    } 
    } 

    /** 
    * Minute key handler, used to monitor "special" keys for the hour field. 
    * 
    * This looks for the user pressing the left arrow key in order to perform 
    * special navigation 
    */ 
    protected class MinuteKeyHandler extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 
     boolean numLock = false; 
     try { 
     numLock = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_NUM_LOCK); 
     } catch (Exception exp) { 
     } 

     if ((e.getKeyCode() == KeyEvent.VK_NUMPAD4 && !numLock) || e.getKeyCode() == KeyEvent.VK_LEFT) { 
     // Only want to move backwards if we are at the first edit position 
     if (fldMin.getCaretPosition() == 0) { 
      moveFocusBackward(); 
     } 
     } 
    } 
    } 

    /** 
    * Hour field focus handler. This watches for focus lost events a 
    * automatically pads the field with a leading "0" if the field is only 1 
    * character in length 
    */ 
    protected class HourFocusHandler extends FocusAdapter { 

    @Override 
    public void focusLost(FocusEvent e) { 
     String text = fldHour.getText(); 
     if (text.length() < 2) { 
     text = pad(text, 2); 
     fldHour.setText(text); 
     } 
    } 
    } 

    /** 
    * Minute field focus handler, watches for focus lost events and automatically 
    * adds a "0" to the end of the field if it is only 1 character in length 
    */ 
    protected class MinuteFocusHandler extends FocusAdapter { 

    @Override 
    public void focusLost(FocusEvent e) { 
     String text = fldMin.getText(); 
     if (text.length() < 2) { 
     fldMin.setText(text + "0"); 
     } 
    } 
    } 

    /** 
    * The document filter used to filter the hour field. 
    */ 
    protected class HourDocumentFilter extends DocumentFilter { 

    @Override 
    public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException { 
     System.out.println("insert: offset = " + offset + "; text = " + text); 
     super.insertString(fb, offset, text, attr); 
    } 

    @Override 
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 

     try { 
     boolean isAcceptable = false; 
     boolean passOnFocus = false; 

     int strLength = text.length(); 
     // We convert the value here to make sure it's a number... 
     int value = Integer.parseInt(text); 

     // If the length of the string been replaced is only 1 character 
     if (strLength == 1) { 
      // If we are at the start of the editing position 
      if (offset == 0) { 
      // What clock type are we using... 
      if (!is24HourClock()) { 
       // only accept 0 or 1... 
       if (value <= 1) { 
       isAcceptable = true; 
       } 
      } else if (value <= 2) { 
       isAcceptable = true; 
      } 
      // If we are at the second editing position 
      } else if (offset == 1) { 
      // Get the preceeding value, should be 0, 1 or 2 
      String upperPart = fb.getDocument().getText(0, 1); 
      // Convert the value to an int 
      int upperValue = Integer.parseInt(upperPart); 

      // The acceptable range of values for the given position 
      int lowerRange = 0; 
      int upperRange = 9; 

      // Which clock are we using 
      if (is24HourClock()) { 
       // If the first value is 2, we can only accept values from 0-3 (20-23) 
       if (upperValue == 2) { 
       upperRange = 3; 
       } 
      } else { 
       // 12 hour clock 
       // If the first value is 1, we can only accept values from 0-2 (10-12) 
       if (upperValue == 1) { 
       upperRange = 2; 
       } 
      } 

      // Is the value within accpetable range... 
      if (value >= lowerRange && value <= upperRange) { 
       isAcceptable = true; 
      } 

      // Pass on focus (only if the value is accepted) 
      passOnFocus = true; 
      } 
     } else { 
      // First, we need to trim the value down to a maximum of 2 characters 

      // Need to know at what offest... 
      // 2 - offset.. 
      // offset == 0, length = 2 - offset = 2 
      // offset == 1, length = 2 - offset = 1 
      strLength = 2 - offset; 
      String timeText = text.substring(offset, strLength); 
      value = Integer.parseInt(timeText); 
      // this will only work if we are using a 24 hour clock 
      if (value >= 0 && value <= 23) { 
      while (value > 12 && is24HourClock()) { 
       value -= 12; 
      } 

      // Pad out the text if required 
      text = pad(value, 2); 
      isAcceptable = true; 
      } 
     } 

     if (isAcceptable) { 
      super.replace(fb, offset, length, text, attrs); 
      if (passOnFocus) { 
      moveFocusForward(); 
      } 
     } 
     } catch (NumberFormatException exp) { 
     } 
    } 
    } 

    /** 
    * The document filter used to filter the minute field. 
    */ 
    protected class MinuteDocumentFilter extends DocumentFilter { 

    @Override 
    public void insertString(FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException { 
     System.out.println("insert: offset = " + offset + "; text = " + text); 
     super.insertString(fb, offset, text, attr); 
    } 

    @Override 
    public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { 

     try { 
     boolean isAcceptable = false; 
     boolean passOnFocus = false; 

     // How long is the text been added 
     int strLength = text.length(); 
     // Convert the value to an integer now and save us the hassel 
     int value = Integer.parseInt(text); 

     // If the length is only 1, probably a new character has been added 
     if (strLength == 1) { 
      // The valid range of values we can accept 
      int upperRange = 9; 
      int lowerRange = 0; 
      if (offset == 0) { 
      // If we are at the first edit position, we can only accept values 
      // from 0-5 (50 minutes that is) 
      upperRange = 5; 
      } else if (offset == 1) { 
      // Second edit position... 
      // Every thing is valid here... 
      // We want to pass on focus if the clock is in 12 hour mode 
      passOnFocus = !is24HourClock(); 
      } 

      // Is the value acceptable.. 
      if (value >= lowerRange && value <= upperRange) { 
      isAcceptable = true; 
      } 
     } else { 
      // Basically, we are going to trim the value down to at max 2 characters 

      // Need to know at what offest... 
      // 2 - offset.. 
      // offset == 0, length = 2 - offset = 2 
      // offset == 1, length = 2 - offset = 1 
      strLength = 2 - offset; 
      String timeText = text.substring(offset, strLength); 
      value = Integer.parseInt(timeText); 
      if (value >= 0 && value <= 59) { 
      // Pad out the value as required 
      text = pad(value, 2); 
      isAcceptable = true; 
      } 
     } 

     if (isAcceptable) { 
      super.replace(fb, offset, length, text, attrs); 
      if (passOnFocus) { 
      moveFocusForward(); 
      } 
     } 

     } catch (NumberFormatException exp) { 
     } 
    } 
    } 

    /** 
    * This is a simple "pass" on action handler... 
    */ 
    protected class ActionHandler implements ActionListener { 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     ActionEvent evt = new ActionEvent(TimeField.this, e.getID(), e.getActionCommand(), e.getModifiers()); 

     fireActionPerformed(evt); 
    } 
    } 

    public static String pad(long lValue, int iMinLength) { 
    return pad(Long.toString(lValue), 2); 
    } 

    public static String pad(int iValue, int iMinLength) { 
    return pad(Integer.toString(iValue), iMinLength); 
    } 

    public static String pad(String sValue, int iMinLength) { 
    StringBuilder sb = new StringBuilder(iMinLength); 
    sb.append(sValue); 
    while (sb.length() < iMinLength) { 
     sb.insert(0, "0"); 
    } 
    return sb.toString(); 
    } 
} 

爲什麼有人選擇了這個龐大的實現,超過了DavidKroukamp的簡單解決方案。另外,手動輸入數字時會出現一些錯誤。我更喜歡DavidKroukamp的方式..

簡單的答案,驗證。 JFormattedTextField不符合該值,但僅限於可輸入數字的事實,您可以輕鬆地將99:99輸入到JFormattedTextField。這個實現的目的是提供實時驗證,同時提供簡單的數據輸入要求

+0

+1高估了我:) – 2012-08-09 10:47:56

+0

有一些較短的聯繫(需要能夠鍵入345以獲得3: 45或34得到3:40)但基本的骨架在那裏;) – MadProgrammer 2012-08-09 10:49:28

+2

謝謝@MadProgrammer。你總是來幫助!我想測試你的代碼。但似乎有一個問題。我粘貼了netbeans。但似乎有些類缺失。你在使用外部庫嗎?我能做什麼? – Anubis 2012-08-09 11:07:11

3

我沒有看到多重JSpinner,或JFormattedTextField任何原因,好好嘗試一下讓我的任何SENCE,這些概念都沒有用戶友好,有看:

+0

+1是的,總是明智地把事情落到實處。這將是一個更好的實現 – 2012-08-09 12:39:10

+1

@mKorbel也許你是對的。但是我發現DavidKroukamp的上面的代碼非常有用。當然,它也非常簡單和用戶友好。無法理解您的評論。如果你能解釋一下你爲什麼這麼說,我會很感激。我的需要只是一個時間領域。不需要輸入日期。 (其實我在一個單獨的字段中使用JXDatePicker獲取日期)。 – Anubis 2012-08-09 14:27:45

+1

@DavidKroukamp你也同意mKorbel。在'FormattedTextField'上選擇'spinner'的任何原因? – Anubis 2012-08-09 14:31:14