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

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.

Related

Design Pattern in Java for Getting Input and Acting on it

I'm trying to make a tic-tac-toe game and I'm encountering a lot of copy-paste work for inputs. I'm trying to figure out what design pattern and implementation works for prompting the user, collecting their input, comparing it and then acting by assigning a value. Right now my code looks like this.
public void promptPlayerCount(BufferedReader in) throws IOException {
String input;
// initial prompt
System.out.println("How many players?");
input = "try again";
while (input.equals("try again")) {
input = in.readLine();
// extract data and check it
switch (Integer.parseInt(input)) {
case 1:
// assignment
playerCount = 1;
break;
case 2:
playerCount = 2;
break;
default:
input = "try again";
// clarified instructions
System.out.println("please enter 1 or 2");
}
}
}
There's a part of me that thinks I could make a function (maybe a factory?) that allows me to generate a function by passing the constructing function the details of the initial prompt, the extraction method, the assignment action and the clarification message.
Would this be best done with lambda functions?
Text input is hard, especially if you can't trust your user (like in a game). Your parseInt will throw a nasty exception right off if your value isn't an integer.
Also standard in is not friendly. I assume this is for an assignment so I won't fault you for using it, but in anything where you don't HAVE to use stdin, don't. The problem is that it's amazingly difficult to get Java to respond to anything less than an entire line with an enter at the end.
When dealing with user input I almost always trim it (Just because they love to insert random white spaces at the beginnings and end) and check to see if it's empty. This could probably be put into a function that also either shows an error or exits the program on "Empty" and otherwise returns a string.
If you often want int values, write a second function that calls the first. Have the second function return an int, but have it catch the exception if the text is invalid and prompt the user again. You could even have this function take a "Range" of integers as a parameter and provide a prompt. So what you have above could look like this:
playerCount = getUserInput("Please enter the number of users", 1, 2);
The rest is wrapped in simple non-redundant functions.
Won't write the code for you because A) it's probably a homework assignment and the fun part is actually coding it and B) someone else probably will provide a full solution with code before I'm done typing this :(
Good luck.

Proximity checker for a ButtonGrid (like minefield game)

I'm writing a code for a treasure hunt game, a grid of buttons and one of them hide the treasure behind it. I want to ad a proximity checker: if the button clicked touch the button with the treasure behind a message appear telling the player that he is near.
This is what i managed to write but i always get a mistake for the arrays going out of bound (this happens because the last row and column aren't surrounded by buttons).
As you can see i put a lot of "if" to contain the chance of goig out of bound but it keeps happening. Any suggestion?
You can use switch-cases here.
switch(grid){
case treasure[x1][y1]:
// your logic
break;
// other cases
default:
// default scenario
}
You need to check the length of the array before you try to access a row beyond it. It appears that you are doing this for values that too low like this:
if (y1 < 0){
y1 = 0;
}
But you need to have a similar check for values that are too high.
Alternatively,
This design could be much cleaner/simpler if you just passed in the X/Y location of the treasure. Instead of the actual JButtons. Then you could just subtract the values to determine if you were close or not.
The way I would do it is to write a function to do the check for a match that also checks for the bounds. For example:
private boolean isTreasureAt(int x, int y) {
if (x<0 || y<0 || x>width || y>height)
return false;
return treasure[x][y]; // need your correct checking logic here
}
Now you can just call isTreasureAt() for whatever co-ordinates you like and its always safe, no need to put range checks everywhere in your code.

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

How to allow only floats in a JTextField in 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
}
}

J2ME TextField Exception

When I instantiate a textField, I have a number in it that I want to be the default text. The problem is, I can't seem to be able to place that value into the textfield without getting an error. The strange thing about it is that the same TextField is what I use to set the value of the variable containing the number.
TextField myTF = new TextField("Number", value, 10, TextField.NUMERIC);
When I run this code, I receive an exception stating that value doesn't match the constraints of TextField.NUMERIC. However, when I check the vale of the value of the variable, I get the following output:
value = 1234567890
value.length() = 10
The value is set by the same TextField, saved to the phone that I am working on, and when loaded from the phone's settings, throws an exception.
This is definitely a JVM bug. If a TextField returned a string, it must be able to accept it. The only thing I can advice is to play a bit with the size of the field or the constraints. You haven't specified the device you are using, there could be some new firmwares for it with bugfixes.
a potential workaround to your problem could be to instantiate the field with a null value and then set the text afterwards.
TextField myTF = new TextField("Number", null, 10, TextField.NUMERIC);
myTF.setString(value);
I have the same problem. The cellphone is trying to store the field value as an int, and the maximum int value is (2^31) - 1 = 2,147,483,647, which is one digit short of what you (and me) need. Workaround, make your field of type text and set a charset of IS_LATIN_DIGITS. Cheers.
My idea is you try it
String str=""+value;
TextField myTF = new TextField("Number",str,10,TextField.NUMERIC);

Categories