JTextField take twice the input, but why?

JTextField take twice the input, but why?



I wanna make a programmable calculator, i got the basic GUI, and now i'm trying to set up the buttons, and the display. My display text will be "0" basically and if the user type in a number, that number should to be displayed. I tried to do it with KeyListener, but if i press a key it will display the key twice. Why?


textField.addKeyListener(new KeyListener()
boolean newNumber = true;

public void keyTyped(KeyEvent e)


public void keyPressed(KeyEvent e)
int keyCode = e.getKeyCode();


if(keyCode == e.VK_BACK_SPACE && textField.getText().length() == 1)
textField.setText("0");
newNumber = true;


if(textField.getText().equals("0") && newNumber)
textField.setText(KeyEvent.getKeyText(keyCode));
newNumber = false;



public void keyReleased(KeyEvent e)


);



Before input:



enter image description here



After "1" input:



enter image description here





Don't use a KeyListener for this purpose, instead, use a DocumentFilter, it's what it's designed for
– MadProgrammer
Sep 1 at 10:36


KeyListener


DocumentFilter





In order to understand "why" this is happening, you need to understand "how" text editing works. Essentially what is happening, is, the keyPressed event is been delivered to your listener, you are setting the text to the value you want. The key event is then delivered to the listener of the JTextField, which is updating the underlying Document (which already contains 1) with the information from the key event, hence it appears twice - this is one of the many reason you don't want to use KeyListener and any one that suggests a "work around" for you to continue to do is a hack
– MadProgrammer
Sep 1 at 10:45


keyPressed


JTextField


Document


1


KeyListener





@MadProgrammer I guess that something like similar, just i dont know how can i fix it. I already used a DocumentFilter in this program, but to be honest, i really dont understand how it is work, so i can not figure it out by my self. I though that i will be much easier, maybe not that nice, but enough for now.
– AME
Sep 1 at 10:51





See also this calculator example. It uses ScriptEngine to evaluate the expression in the text field.
– Andrew Thompson
Sep 2 at 1:08


ScriptEngine




2 Answers
2



Here a simple solution:



If you use keyPressed, you have to do something in keyReleased and this become
complicated. keyTyped is a more simple way.


keyPressed


keyReleased


keyTyped



You can use e.consume() to prevent having the double digit inserted.


e.consume()


textField.addKeyListener(new KeyListener()

int codeDelete = KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_DELETE);
int codeBackSpace = KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_BACK_SPACE);

@Override
public void keyTyped(KeyEvent e)

char keyChar = e.getKeyChar();

if (textField.getText().length() == 0)
textField.setText("0");

else if (textField.getText().equals("0") && keyChar != codeDelete && keyChar != codeBackSpace)
textField.setText(String.valueOf(e.getKeyChar()));
e.consume();



@Override
public void keyPressed(KeyEvent e)


@Override
public void keyReleased(KeyEvent e)


);





You can use KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_DELETE) and KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_BACK_SPACE) to avoid these magic values.
– smillien62
Sep 3 at 0:24


KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_DELETE)


KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_BACK_SPACE)





Yes ! It is exactly what I am looking for :-) I will edit my post. Thanks.
– Arthur
Sep 3 at 0:26



For doing that, I derive PlainDocument like this:


import java.awt.EventQueue;
import java.util.regex.Pattern;

import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class DigitDocument extends PlainDocument

private static final long serialVersionUID = 1L;
protected static final Pattern patternStartZero = Pattern.compile("^0.+");

protected final JTextField textField;

private final int limit;
private final Runnable runnableFormat;

public DigitDocument(JTextField textField, int limit)

super();

this.textField = textField;
this.limit = limit;

runnableFormat = new Runnable()

@Override
public void run()

String text = textField.getText();

if (text.length() == 0)
textField.setText("0");

else if (patternStartZero.matcher(text).matches())
textField.setText(text.replaceAll("^0+", ""));


;


@Override
public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException

str = str.replaceAll("[^0-9]", "");

if (str.length() == 0)
return;

else if ((getLength() + str.length()) <= limit)
super.insertString(offset, str, attr);

EventQueue.invokeLater(runnableFormat);


@Override
public void remove(int offs, int len) throws BadLocationException
if (!"0".equals(textField.getText()))
super.remove(offs, len);

EventQueue.invokeLater(runnableFormat);




The usage is:


textField.setDocument(new DigitDocument(textField, 10));
textField.setText("0");



In DigitDocument,





Use a DocumentFilter as has already been suggested. The DocumenFilter is designed so you don't need to create custom Documents. Instead you create the filter and add it to the document. There is no need for all the synchronized code. Swing events execute on the Event Dispatch Thread (EDT) already.
– camickr
Sep 1 at 14:44





Thanks for edit and comment. invokeLater is still necessary, it doesn't work without.
– Arthur
Sep 1 at 15:04





It wont solve my problem. As i mentioned, i already have a document filter, however i really dont understand exactly, how is it work but i guess it does the same, but not solve my problem.
– AME
Sep 1 at 16:42



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Some of your past answers have not been well-received, and you're in danger of being blocked from answering.



Please pay close attention to the following guidance:



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)