Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to constrain user to enter a time in a JTextField

In one of my java applications, there is a field where the user is supposed to enter a time. I know, I can simply keep it as a normal JTextField and at the time of validation I can check the value and so on...

But I think there is a better way than that..

For example, if this is a matter with a date, then JXDatePicker (which comes with swingx) can be used very handily. Eventually, the users selection is guaranteed to be a date.

Likewise, there must be a better way for time selection too. Will someone share your knowledge if you know a better solution.

Any thought is appreciated. Thank you!

like image 828
Anubis Avatar asked Aug 09 '12 10:08

Anubis


3 Answers

you could use a JFormattedTextField have a look at the example below, this will create a JFormattedTextField which will accept only numbers and put them in the form XXhXXminXXs then add a ActionListener to the JFormattedTextField and in that attempt to parse to a valid time object when ENTER for now I only show the use of the JFormattedTextField and the ActionListener I didn't attempt to convert or any converting and parsing for valid time:

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();
            }
        });
    }
}
like image 99
David Kroukamp Avatar answered Nov 06 '22 22:11

David Kroukamp


  • Multiple JSpinner instances allowing to select hours, minutes and seconds
  • Use a JFormattedTextField with some improvements to provide immediate user feedback (for example color the background red as soon as the input becomes invalid)
like image 40
Robin Avatar answered Nov 06 '22 23:11

Robin


I did a prototype of a TimeField some time ago, it still needs a little work, but the concept is pretty basic.

It basically presents two JTextFields, one for the hour and one for the minutes and makes them appear to be a single field.

Through the use of some DocumentFilters, it restricts the users input.

enter image description here

I did this some time ago and it needs work, but the basic idea is there...if you have problems, you will need to try and figure it out yourself ;)

/**
 *
 * @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();
  }
}

why should someone chose this bulky implementation over above given DavidKroukamp's simple solution. Also, this has some bugs when manually entering numbers. I prefer DavidKroukamp's way..

Simple answer, validation. JFormattedTextField does not valid the values, but only limits the fact that you can enter digits, you could just as easily enter 99:99 into a JFormattedTextField. The intention of this implementation is to provide real time validation while providing simple data entry requirements

like image 32
MadProgrammer Avatar answered Nov 06 '22 22:11

MadProgrammer