3

In my application I want to input numbers (amounts) to a specific limit, and hence have used JFormattedTextField. Limit like "12345678.99" i.e. 8 digits before "." and 2 after "." or so on. This is my implementation code, but it doesn't result as expected.

    startBalTxt.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("########.##"))));
    startBalTxt.setText(resourceMap.getString("startBalTxt.text")); // NOI18N
    startBalTxt.setFont(Utility.getTextFont());
    startBalTxt.setName("startBalTxt"); // NOI18N

  INPUT                RESULT  
"12345678905.99"   => "12345678906"      ==> Should give "12345678.99" or "12345679.99"
"12345678.555"     => "12345678.56"      ==> CORRECT
"1234567890123456" => "1234567890123456" ==> Absolutely wrong in all aspects

Where am I going wrong ? And how to make this working as I am expecting it.

UPDATIONS AS PER SUGGESTED by StanislavL :

    numberFormat = (DecimalFormat) DecimalFormat.getNumberInstance();
    numberFormat.setMaximumFractionDigits(2);
    numberFormat.setMaximumIntegerDigits(8);
    numberFormat.setMinimumFractionDigits(0);
    numberFormat.setMinimumIntegerDigits(2);

    nfr = new NumberFormatter(numberFormat);

    initComponents();
    myParent = parent;
    this.startBalTxt.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(nfr));

    Results ->  4562147896.45  == > 62,147,896.45

Its obeying the limit that's true, but its eliminating previous numbers instead of later. I mean in 4562147896.45 instead of "45" "96" shouldn't be eliminated.

Tvd
  • 4,463
  • 18
  • 79
  • 125

2 Answers2

7

Pass DecimalFormat to the JFormattedTextField constructor. It has following methods

setMaximumIntegerDigits
setMinimumIntegerDigits
setMaximumFractionDigits
setMinimumFractionDigits
mKorbel
  • 109,525
  • 20
  • 134
  • 319
StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • 1
    Actually, I am using NetBeans. Can't modify the constructor. Got to use FormatFactory only to set it. Added above code and also shwn the results in thee. – Tvd Dec 20 '11 at 09:50
  • @Tvd if a tool stands in your way, don't use it. At least _completely_ learn all its possibilities (pretty sure - as in guessing around, never use it myself - it supports all constructors) – kleopatra Dec 20 '11 at 10:27
  • Can that elimination of digits be handed out - as mentioned in the question at bottom. – Tvd Dec 20 '11 at 10:55
  • How can I restrict integer digits to only 8 - after 8 digits it beeps or doesn't allow input any such sort of indication for the user ???? – Tvd Dec 20 '11 at 11:17
3

even JFormattedTextField implements DecimalFormat and NumberFormat, better would be use DocumentListener,

1) its not good jumping betweens Big Figures by using DecimalFormat or NumberFormat simple User-non-Acceptable by implements setMinimum() and setMaximum()

2) JTextComponents by default implements insert the text, then any workaround is so User-non-Acceptable by implementsJFormattedTextField with DecimalFormat orNumberFormat by implements setMinimum() and setMaximum()

3) its very confortable je use DocumentListener allows add any amount, but with highlighting out-off range

4) or use JSpinner with SpinnerNumberModel, there is posible to set Formatter as for Number Instance

example for InternationalFormatter and DocumentListener together

import java.awt.*;
import java.awt.font.TextAttribute;
import java.math.*;
import java.text.*;
import java.util.Map;
import javax.swing.*;
import javax.swing.JFormattedTextField.*;
import javax.swing.event.*;
import javax.swing.text.InternationalFormatter;

public class DocumentListenerAdapter {

    public static void main(String args[]) {
        JFrame frame = new JFrame("AbstractTextField Test");
        final JFormattedTextField textField1 = new JFormattedTextField(new Float(10.01));
        textField1.setFormatterFactory(new AbstractFormatterFactory() {

            @Override
            public AbstractFormatter getFormatter(JFormattedTextField tf) {
                NumberFormat format = DecimalFormat.getInstance();
                format.setMinimumFractionDigits(2);
                format.setMaximumFractionDigits(2);
                format.setRoundingMode(RoundingMode.HALF_UP);
                InternationalFormatter formatter = new InternationalFormatter(format);
                formatter.setAllowsInvalid(false);
                formatter.setMinimum(0.0);
                formatter.setMaximum(1000.00);
                return formatter;
            }
        });
        final Map attributes = (new Font("Serif", Font.BOLD, 16)).getAttributes();
        attributes.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
        final JFormattedTextField textField2 = new JFormattedTextField(new Float(10.01));
        textField2.setFormatterFactory(new AbstractFormatterFactory() {

            @Override
            public AbstractFormatter getFormatter(JFormattedTextField tf) {
                NumberFormat format = DecimalFormat.getInstance();
                format.setMinimumFractionDigits(2);
                format.setMaximumFractionDigits(2);
                format.setRoundingMode(RoundingMode.HALF_UP);
                InternationalFormatter formatter = new InternationalFormatter(format);
                formatter.setAllowsInvalid(false);
                //formatter.setMinimum(0.0);
                //formatter.setMaximum(1000.00);
                return formatter;
            }
        });
        textField2.getDocument().addDocumentListener(new DocumentListener() {

            @Override
            public void changedUpdate(DocumentEvent documentEvent) {
                printIt(documentEvent);
            }

            @Override
            public void insertUpdate(DocumentEvent documentEvent) {
                printIt(documentEvent);
            }

            @Override
            public void removeUpdate(DocumentEvent documentEvent) {
                printIt(documentEvent);
            }

            private void printIt(DocumentEvent documentEvent) {
                DocumentEvent.EventType type = documentEvent.getType();
                double t1a1 = (((Number) textField2.getValue()).doubleValue());
                if (t1a1 > 1000) {
                    Runnable doRun = new Runnable() {

                        @Override
                        public void run() {
                            textField2.setFont(new Font(attributes));
                            textField2.setForeground(Color.red);
                        }
                    };
                    SwingUtilities.invokeLater(doRun);
                } else {
                    Runnable doRun = new Runnable() {

                        @Override
                        public void run() {
                            textField2.setFont(new Font("Serif", Font.BOLD, 16));
                            textField2.setForeground(Color.black);
                        }
                    };
                    SwingUtilities.invokeLater(doRun);
                }
            }
        });
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(textField1, BorderLayout.NORTH);
        frame.add(textField2, BorderLayout.SOUTH);
        frame.setVisible(true);
        frame.pack();
    }

    private DocumentListenerAdapter() {
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • excellent example. I didn't get your 1st point - why User-non-accepteble ? While surfing for solution for the above I read many times developers say its not good to use DocumentListener for such tasks instead one should use formatter only. One reason I could find is DocumentListenr shows results after we have moved from that textfield whereas formatter will show on spot only. Can you pour some light on this. – Tvd Dec 21 '11 at 06:02
  • 1
    @Tvd I forgot to add setMinimum() and setMaximum() to my answer, there no going about developers like or wharever, is about user_freindyl, really moving inside alloved possitions is terrible, – mKorbel Dec 21 '11 at 07:33
  • If I add setMinimum & setMaximum to textfield2's formatter, then printIt() of DocumentListener is never active. Even if I try to do Copy-Paste then also the formatter only takes care and doesn't allow to paste invalid data. If I got to implement formatter & DocumentListener (as done for textfield2) and formatter only looks up mostly then where & when DocumentListener comes under picture ?? – Tvd Dec 21 '11 at 10:45
  • 1
    right, but problems cames when you touched limits with Focus or http://stackoverflow.com/questions/7378821/jformattedtextfield-issues – mKorbel Dec 21 '11 at 10:54
  • Right @mKorbel. Thanks for clarifications. And yes, I have another formattedtextField where I have set Mask and in that field I see what you are saying in the above link. I tried to add the DocumentListner as shown in your query. But couldn't get any way to implement trashTest's solution wher I have just JFT's. Can you show some guideline. Thanks a lot. – – Tvd Dec 21 '11 at 13:07
  • FocusListener helped me do my job. Added focusGained and in SwingUtilities.invokeLater() checked if (ftf.getValue() == null) then I set its value and text to "". This puts the caret sign on 0th element. This works with mouse and Tab, Shift-Tab. I had problem with mouse click only. – Tvd Dec 21 '11 at 13:39