I'm trying to learn something about GUI, using NetBeans6.8, starting with the GUI section in The java tutorial.
There is a simple exercise for a Celsius-Fahrenheit converter. I want that to have two TextFields, one for Celsius and one for Fahrenheit temperature; if the user types in the celsius text field he got the result "printed" in the fahrenheit text filed. and vice versa.
So, i put on both the textfields one KeyTyped event, here's the code:
private void celsiusTextKeyTyped(java.awt.event.KeyEvent evt) {
int cels = Integer.parseInt(celsiusText.getText());
int fahr = (int)(cels * 1.8 + 32);
fahrText.setText(fahr + "");
}
private void fahrTextKeyTyped(java.awt.event.KeyEvent evt) {
int fahr = Integer.parseInt(fahrText.getText());
int cels = (int)(fahr / 1.8 - 32);
celsiusText.setText(cels + "");
}
It doesn't work. If i type something in a textfield i got this exception: java.lang.NumberFormatException: For input string: ""
The code that attach the listeners:
celsiusText.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
celsiusTextKeyTyped(evt);
}
});
fahrText.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyTyped(java.awt.event.KeyEvent evt) {
fahrTextKeyTyped(evt);
}
});
[However, i can't modify it, it's autogenerated.]
Method .getText() returns a string not a number, if that string contains non-numeric characters (i.e. a letter, a space, nothing at all) then parseInt will throw a NumberFormatException. Since your using KeyEvent, as soon as you press say "7", the event is fired before 7 is entered into the text box. Thus the text box still only contains "", which is where the error comes from. You may wish to also listen to the keyUp event instead.
You need to enclose your code in a try catch block.
private void fahrTextKeyTyped(java.awt.event.KeyEvent evt)
{
try
{
int fahr = Integer.parseInt(fahrText.getText());
int cels = (int)(fahr / 1.8 - 32);
celsiusText.setText(cels + "");
}
catch(NumberFormatException ex)
{
//Error handling code here, i.e. informative message to the user
}
}
An alternative is you could filter out non-numbers on keydown event, see example here - http://www.javacoffeebreak.com/java107/java107.html (Creating a custom component - NumberTextField)
I suspect that what's happened is that you added these handlers with something like celsiusText.addKeyListener, yes?
The thing is, that'll give you not just the KEY_TYPED events you wanted, but also KEY_DOWN and KEY_UP. The KEY_DOWN event will happen before the text is really entered into the field, so your code firing on that will see the field as blank still. Trying to convert the empty string to a number gives you a format exception.
The easiest way to fix this is the try/catch construct other people have been posting.
You probably set action to keyDown, this mean that even occur before the key value is "added" to textbox, while You retrieve the value from it is still empty "".
There is a simple exercise for a
Celsius-Fahrenheit converter
That is a really old example. The better approach is to use a DocumentListener, not a KeyListener.
Related
For my current project I need to create a custom text box that gets each key pressed and adds it to a string. I'm constantly updating the method that retrieves the key a user is pressing and then I add it like so:
public void addCharacter(String c) {
String before = text;
String after = before;
if (!before.endsWith(c)) {
after = text + c;
} else {
//What can I do here to check if the key
//was released and then pressed again, so that
//it only adds the character the number of times the user presses the key.
}
text = after;
}
My problem is that if I type a key it adds tons of them because of the fact that it is constantly updating, which is why I had to check if it's the same letter as before, and not add it.
EDIT:
Example of how we add the key:
if (key.a) {
addCharacter("a");
return;
}
I think you can get the job done by using a KeyListener. This is basically a listener which sends events each time a key is typed, pressed and released. In a nutshell, I would listen to a keyPressed event and then I would not type that letter until I receive a keyReleased event.
In my swing application I want to echo jpassword field character for some time (1 second) and then again hide it. I want to do it character by character after user inputs a character (When user inputs a character, show it, then hide it. Then for all input characters repeat this).
Can someone tell me is it possible, if yes how?
Thanks in advance!
It's not very complicated, you can disable the masking characters when you set this value to “0″ with this method: setEchoChar((char) 0)
pass.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
unhide();
}
public void removeUpdate(DocumentEvent e) {
unhide();
}
public void insertUpdate(DocumentEvent e) {
unhide();
}
public void unhide(){
pass.setEchoChar((char) 0);//display password
//here your timer
pass.setEchoChar('*');//hide with '*'
}
});
The code above shows you a first idea of what you should do. You'll have to use a thread to wait for the desired time.
I came across this which may be a good start as it displays the last char entered and shows the rest of the password is masked but doesn't hide it after a set time so you would probably need to implement an event to hide after set time Check it out here
i have a JFormattedTextField , and i want that when i try to enter a number, example 1002 , that i will rounded to the nearest multiple of 5
1002->1000
304->305
6->5
9->10
1->0
etc..
i've already setup a number format to cancel the grouping, and accepting only numbers
NumberFormat format=NumberFormat.getInstance();
format.setGroupingUsed(false);
pun1[i]=new JFormattedTextField(format); //pun1 and pun2 are the arrays of FIELDS
pun2[i]=new JFormattedTextField(format);
how can i resolve this problem?
I want this editing inside the field, while i'm writing the number, just as when the grouping character appears!
This works for int arguments:
public int roundToClosestFive(int num) {
return (int) (Math.round(num / 5.0) * 5);
}
Remember, to get the int value of the string you've entered you can do: Integer.valueOf(string); and pass that as an argument to the method. To have the text inside the JFormattedTextField change on focus change or enter, you could call the above method from the propertyChange() method of a PropertyChange listener that you can add to the JTextFormattedTextField. Something like this in the propertyChange() method:
public void propertyChange(PropertyChangeEvent e) {
Object source = e.getSource();
if (source == pun1[i]) {
((JFormattedTextField) source).setText(""
+ roundToClosestFive(((Number)pun1[i].getValue()).intValue()));
}
}
Does anyone know how to go about creating field that would perform telephone number format masking, like here (___) ___-____:
http://www.smartclient.com/smartgwt/showcase/#form_masking
A better approach would be to let the user type whatever they want: "789-555-1234" or "(789) 555-1234" or "7895551234" and then when the field loses focus decide if what they typed can be a phone number. If so you can reformat it as "(789) 555-1234". There are several related questions about how to do that sort of thing with regular expressions; just be sure your regex accepts the format you're changing the user's input to, otherwise it will be really annoying to edit.
As an example, look what happens when you type ".5" into the left margin field in Microsoft's standard page setup dialog: when you tab out it changes it to "0.5".
UPDATE: Here's sample code in GWT to illustrate. For the sake of this example, assume there's an element called "phoneContainer" to put the text box in. GWT doesn't give you the full java.util.regex package, but it gives enough to do this:
private void reformatPhone(TextBox phoneField) {
String text = phoneField.getText();
text = text.replaceAll("\\D+", "");
if (text.length() == 10) {
phoneField.setText("(" + text.substring(0, 3) + ") " + text.substring(3, 6) + "-" + text.substring(6, 10));
}
}
public void onModuleLoad() {
final TextBox phoneField = new TextBox();
RootPanel.get("phoneContainer").add(phoneField);
phoneField.addBlurHandler(new BlurHandler(){
public void onBlur(BlurEvent event) {
reformatPhone(phoneField);
}
});
}
It looks like you'd want to create your own widget that extends the GWT input box and has a default value set to the mask you want. Then you handle the onKeypress event and update the field as needed (making sure to set the cursor position to the correct location).
I am building a GWT component to behave much like the comments box here on stackoverflow, and other sites. I am trying to register listeners for KeyPress, Change and ONPASTE events that will update my status line with number of characters remaining, etc.
It works except it is always one character behind the actual number of characters in the text area. I set the max number of characters to 10. When I type the first character it still says, "10 characters remaining". It doesn't update the status line until I type the second character and then it is one off, it says 9 characters remaining when the second character is typed.
When I BACKSPACE or DELETE, it is also one off, when there are no characters it still says "9 characters remaining" until I press the BACKSPACE or DELETE a second time.
I am getting this behavior in both Firefox, Chrome and Internet Explorer on Windows. So I think I am not registering something correctly.
I know this has something to do with when the events are getting fired, but I have spend hours on trying to diagnose this behavior and have run out of ideas.
Here is where I am registering the event handlers, the complete code is BoundedTextAreaWithFeedback.
private void registerHandlers()
{
final BoundedTextAreaWithFeedback outer = this;
this.textArea.addChangeHandler(new ChangeHandler()
{
public void onChange(final ChangeEvent changeEvent)
{
outer.validate();
}
});
this.textArea.addKeyPressHandler(new KeyPressHandler()
{
public void onKeyPress(final KeyPressEvent keyPressEvent)
{
outer.validate();
}
});
this.panel.addFocusHandler(new FocusHandler()
{
public void onFocus(final FocusEvent focusEvent)
{
outer.textArea.setFocus(true);
}
});
// capture paste events
this.textArea.sinkEvents(Event.ONPASTE);
}
Here is the validate() method.
private boolean validate()
{
final boolean isValid;
final int len = this.textArea.getText().length();
if (len < this.minLength)
{
this.status.setText("Enter at least " + this.minLength + " characters.");
this.status.setStyleName("input-status-underflow");
isValid = false;
}
else if (len > this.maxLength)
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-overflow");
isValid = false;
}
else
{
this.status.setText(this.maxLength - len + " characters remaining");
this.status.setStyleName("input-status-ok");
isValid = true;
}
return isValid;
}
I just started adding every addXXXHandler() until one worked.
this.textArea.addKeyUpHandler(new KeyUpHandler()
{
public void onKeyUp(final KeyUpEvent event)
{
outer.validate();
}
});
Seems to have done the trick.
Here is the working code, CTRL-V and paste from context menu also work now.
Try using a DeferredCommand to execute the validation code. I believe the problem is that when the event is firing, they character is not yet added to the text area. The DeferredCommand will not execute until any pending event handlers have finished, allowing the length of the text to be calculated correctly.
See this question for an example of using a DeferredCommand.