How to allow only floats in a JTextField in Java - java

I am trying to add a simple currency converter tool to my program yet I hit barrier. Is there a simple way of only allowing float numbers as input to a JTextField in Java. From what I have read online, using JFormattedTextField is a pain to use. Would I need to create a class to do some filtering?

JFormattedTextField shouldnt be all too dificult. Just need to pass in a Formatter in as a parameter and should take care of itself. you can get that from the java API which would use the region settings like so:
new JFormattedTextField(java.text.NumberFormat.getCurrencyInstance());

It would be better to use JFormattedTextField.
Formatted text fields provide a way for developers to specify the valid set of characters that can be typed in a text field. Specifically, the JFormattedTextField class adds a formatter and an object value to the features inherited from the JTextField class. The formatter translates the field's value into the text it displays, and the text into the field's value. See examples.

You can use JFormattedTextField, but it gives a really terrible user experience. Better to discard inappropriate characters as the are entered. DocumentFilter provides a relatively (for Swing) clean way to do this. (Edit: Original answer had links to a trivial example I wrote on my now defunct blog.)

I agree with vcetinick because JFormattedTextField is useful for formatting text input.
However, if you want to verify the value inputted in JTextField, you may need to implement ActionListener yourself:
public void actionPerformed(ActionEvent evt) {
JTextField textfield = (JTextField)evt.getSource();
String strTextValue = textfield.getText();
try {
if (strTextValue.equals("")) {
// Handle empty string
} else {
double dValue = Double.parseDouble(strTextValue);
// Handle valid value
}
} catch (Exception e) {
// Handle invalid value
}
}

Related

Vaadin 14 Textfield format with thousand separators while typing

I'm using Vaadin 14 + Java and I want to display a textfield with monetary values including thousands separators while typing.
The separators get displayed if I load the object into my form and the textfield, but whenever I type a new value or change the existing value, the thousand-seperators doesn't show up / does not update until I saved the object to the database and got the object again.
I set the ValueChangeMode already EAGER, but I suppose the converter only gets applied when writing / loading from the database.
How can I insert/update thousand-separators on the fly while typing?
Example: When i type "1000000", I want the textfield to update to "1.000" after I typed the third zero, and to "10.000" after the next one, then "100.000" and finally "1.000.000" after the sixth and last zero.
Textfield:
money_tf = new TextField("Money in €");
money_tf.setSuffixComponent(new Span("€"));
money_tf.addThemeVariants(TextFieldVariant.LUMO_ALIGN_RIGHT);
money_tf.setValueChangeMode(ValueChangeMode.EAGER);
Binder
binder = new BeanValidationBinder<>(MyClass.class);
binder.forField(money_tf).withConverter(new PriceConverter()).bind("money");
my PriceConverter:
private static class PriceConverter extends StringToBigDecimalConverter {
public PriceConverter() {
super(BigDecimal.ZERO, "Cannot convert to decimal value.");
}
#Override
protected NumberFormat getFormat(Locale locale) {
final NumberFormat format = super.getFormat(locale);
format.setGroupingUsed(true); // enabled thousand separators
if (format instanceof DecimalFormat) {
// Always display currency with two decimals
format.setMaximumFractionDigits(2);
format.setMinimumFractionDigits(2);
}
return format;
}
}
I set the ValueChangeMode already EAGER, but I suppose the converter only gets applied when writing / loading from the database.
This works, but server round trip is involved. If you do not have set-up automatic commit of every change to backend, the database is not update on every letter, only when you call explicitly binder.writeBean(..) and commit the changes to database. In fast typing on slow networks the user experience may not be the best possible.
How can I insert/update thousand-separators on the fly while typing?
I understand your question as, can the conversion be done in the client side, i.e. Browser. And the answer is yes. For simple cases you can use textField.setPattern(regexp) where regexp is a String with regular expression pattern. For more complex scenarios it requires of course some JavaScript logic, but do not worry, there is TextField Formatter add-on in the Directory, that wraps Cleave JS library and gives you nice Java API for this purpose.
Alternatively you can use BigDecimalFieldField component of the framework, which also limits the input to certain number format. The value type of that field is not String, but BigDecimal.

Constrain numeric value in JTextField to a specific range, with defaults

Not sure how to write this in JAVA...
I need to code that will insert a default value (say 50) if user keys in a value outside of a given range of 10-100 feet. I have it working for errors if blank or non integer is entered or value is outside the range but cannot figure out how to integrate a default.
What I have that works is
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout());
poolLength = new JTextField(10);
panel1.add(new JLabel("Enter the pool's length (ft):"));
panel1.add(poolLength);
What I want to add is something like this
If poolLength <10 or >200 then poolLength = 100
Else this.add(panel1);
The simplest way is to get the text during e.g. an ActionEvent, parse it and reset the text if it's outside the range.
jTextField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean isValid = true;
try {
int intVal = Integer.parseInt(jTextField.getText());
if (intVal < 10 || intVal > 200) {
isValid = false;
}
} catch (NumberFormatException x) {
// user entered something which is not an int
isValid = false;
}
if (!isValid) {
jTextField.setText("100");
}
}
});
Also see How to Use Text Fields.
Another way would be to use a spinner which does something like this by default.
disclaimer: I do not know Swing well, actually, I dont remember much at all..
Maybe you simply need to attach a validator to your JTextField?
Here you have an example, however please notice that in that post they check for the length of the text, not the contents. But having the text, you can easily parse it as a number and check if it is greater/lower than the bounds.
As you see in that post, by returning true/false you will prevent the user from entering a wrong value - ie. too small. Now, when wrong value is detected, then, instead of returning 'false', maybe it is possible to simply myjtextfield.setText("50.0") on that input? That may do exactly what you wanted.
really, be careful with those "maybe"s: I do not know Swing, but from general UI framework design, trying to "setText" may:
throw an exception: many frameworks think it's quite evil to change the field's value during validation and defend themselves against it
cause strange issues when editing: if that JTextEdit calls validation upon every single change of the text, you will notice odd things when trying to, i.e. select-all, delete, write 123. You'll end up with 50.0123 or 12350.0 as the JTextEdit might try to validate the intermediate empty text after deletion and coerce it to "50.0"..
or, it may just work.
So, if your time is critical, just try it. Maybe I guessed well. But, if you have some time to spare, wait until someone checks that I didn't write any nonsense.
Use a JSpinner instead.
It will not behave exactly as described, but provide a better user experience. The user can adjust the value with the ↑/↓ buttons. If they type a value outside the specified range, it will revert to the last valid value when the field loses focus.

How to make JFormattedTextField accept integer without decimal point (comma)?

I used JFormattedTextField withNumberFormat in this way:
-Creat a JFormattedTextField refernce
JFormattedTextField integerField;
-Create a NumberFormat refernce
NumberFormat integerFieldFormatter;
-In the constructor:
integerFieldFormatter = NumberFormat.getIntegerInstance();
integerFieldFormatter.setMaximumFractionDigits(0);
integerField = new JFormattedTextField(integerFieldFormatter );
integerField.setColumns(5);
..........
I meant to use it with integer numbers only, but when I type numbers like 1500 it is converted after losing focus to 1,500 , and exception thrown this is the first line of it:
Exception in thread "AWT-EventQueue-0"
java.lang.NumberFormatException: For input string: "1,500"
When I use JTextField instead of JFormattedTextField All integers accepted normally, But the reason why I want to use JFormattedTextField is to benefit from its input restriction advantages.
I realize this is an old question but I just stumbled upon it through the same issue. As the other answers seemed like workarounds to me, I took a closer look at the NumberFormat methods.
I found that the easiest approach would actually be to simply deactivate grouping on the NumberFormat instance:
NumberFormat integerFieldFormatter = NumberFormat.getIntegerInstance();
integerFieldFormatter.setGroupingUsed(false);
That way no group delimiters will appear in the textfield output.
Of course you will also not be able to use them for your input, but that was not intended by the question, right?
Also for an integer instance of NumberFormat you don't need to explicitly setMaximumFractionDigits(0), as that is part of what getIntegerInstance() does for you.
I discovered the solution to my problem; Here it is:
The exact problem is that when I use JFormattedTextField with NumberFormat, the JFormattedTextField adds comma ',' before any next 3 digits for example
1000 rendered as 1,000
10000 rendered as 10,000
1000000 rendered as 1,000,000
When I read an integer value from JFormattedTextField usign this line of code
int intValue = Integer.parseInt(integerField.getText());
The comma is read as part of the string; 1000 read as 1,000 and this string value cannot be converted to integer value, and so exception is thrown.
Honestly the solution is in this Answer but I will repeat it here
use str.replaceAll(",","")
int intValue = Integer.parseInt(integerField.getText().replaceAll(",", ""));
This will replace any comma charachter ',' in the returned string and will be converted normally to int as expected.
Regards
You can do it in (at least) 2 ways:
Using a keyListener
Using DocumentFilter
if you want to use KeyListener:
KeyListener listener = new KeyAdapter(){
public void keyTyped(KeyEvent e){
if(e.getKeyCode()<KeyEvent.VK_0||e.getKeyCode()>KeyEvent.VK_9{//input<'0' or input>'9'?
e.consume();//delete the typed char
}
}
}
yourTextField.addKeyListener(listener);
to use the DocumentFilter check this link: How to allow introducing only digits in jTextField?
EDIT: i forgot to say this. As MadProgrammer said in the first comment to this answer, KeyListener is not the proper way to do it, because
You do not know in what order KeyListeners will be notified of the event and the key may have already gone to the text component before it reaches you (or it could have been consumed before it reaches you)
EDIT #2: ANOTHER QUICK WAY
MaskFormatter formatter = new MaskFormatter("#####");
JFormattedTextField field = new JFormattedTextField(formatter);
And the trick should be done. with this you can insert up to 5 digits in tour textfield, more '#' in the string parameter for the formatter = more digits can be typed by the user
Try this, This is a complete solution for creating and validating number JTextField
NumberFormat format = NumberFormat.getInstance();
format.setGroupingUsed(false);//Remove comma from number greater than 4 digit
NumberFormatter sleepFormatter = new NumberFormatter(format);
sleepFormatter.setValueClass(Integer.class);
sleepFormatter.setMinimum(0);
sleepFormatter.setMaximum(3600);
sleepFormatter.setAllowsInvalid(false);
sleepFormatter.setCommitsOnValidEdit(true);// committ value on each keystroke instead of focus lost
JFormattedTextField textFieldSleep = new JFormattedTextField(sleepFormatter);
textFieldSleep.setText("0");

Find/Replace dialog on jTextArea

I have assigment to make notepad using NetBeans Java. I already made the whole thing, I just don't know how to implement find/replace dialog, can you help me with this. I'm using jTextArea.
I will assume that you already know about Swing and how to make the appropriate dialog box (since you apparently have already made the JTextArea for the Notepad equivalent), and that you just want to know how to make it work on the back end.
What I would do is have a Scanner object go through your file to perform the find and replace.
String myAlteredText = "";
Scanner scanner = new Scanner(myText);
while(scanner.hasNext()) {
String next = scanner.next();
if(next.equals(userFindInput)) {
myAlteredText += userReplaceInput;
}
else {
myAlteredText += next;
}
myAlteredText += " ";
}
You can use .equalsIgnoreCase() if case doesn't matter. Likewise, you can tweak to adjust to your user parameters (i.e., if it doesn't have to match the whole word, use .contains() instead). There may be some nit-picky other things you need to do to maintain abnormal spacing and line breaks, but this is the general approach I would use.
You could use a JTable although this is rather unconventional. You could load each word into a new cell. This way when you need to replace 1 word you don't need to update the entire jtextarea for just 1 character unless I am mistaken. This would require a lot of work however in order to get this to work

Java JFormattedTextField for typing dates

I've been having trouble to make a JFormattedTextField to use dates with the format dd/MM/yyyy. Specifically, as the user types, the cursor should "jump" the slashes, and get directly to the next number position.
Also, the JFormattedTextField must verify if the date entered is valid, and reject it somehow if the date is invalid, or "correct it" to a valid date, such as if the user input "13" as month, set it as "01" and add +1 to the year.
I tried using a mask ("##/##/####") with the validate() method of JFormattedTextField to check if the date is valid, but it appears that those two don't work well together (or I'm too green on Java to know how... :), and then the user can type anything on the field.
Any help is really appreciated! Thanks!
try using JCalendar
You may have to use a regular JTextField and call setDocument() with a custom document. I recommend extending PlainDocument, this makes it easy to validate input as the document changes, and add slashes as appropriate.

Categories