Java JTextField text length not updating after deleting characters - java

I am trying to create a JTextField with a key listener that will enable a button only when the length of the text is exactly 4.
It's working but if length of 4 is reached, and I delete a character (using backspace or delete buttons) the text length isn't updated and keeps being 4, until I remove another character, but that will make it actually 2 characters.
Can you help me with the code to make it update the length? Thanks in advance.
I already tried these without success:
Document doc = field.getDocument();
if (doc.getLength() > 0) {
try {
doc.remove(field.getCaretPosition(), 1);
} catch (BadLocationException e1) {
}
}
and
field.setText(field.getText().substring(0, field.getText().length()));

Found the error:
I was calling the method to enable the button in the KeyListener's keyTyped method, instead of doing it in keyReleased method.
That simple change, made the code work as expected.

Related

Storing text as an arraylist from JTextArea

I need to create a program to store all words in an array list. Then check the user input from the textfield to see if it starts with anything other than numbers and punctuation. Otherwise it will need to display an error and prvent the string to be added to the arraylist and display an appropriate error.
https://pastebin.com/8UwDm4nE
Heres the ActionEvent listener that contins the code to check that. Im not really sure how to get it working.
#Override
public void actionPerformed(ActionEvent e) {
for(int i = 0; i < 1; i++) {
String str = tf.getText(); // MUST BE STORED ON AN ARRAY LIST
ta.append(str + "\n"); // Append the text on new line each
if(str.startsWith(String.valueOf(nums))) { // Check input for a number at the start
error.setText("Error: Word starts a number. Please try again!");
error.setForeground(Color.RED);
ta.append("");
} else if (str.startsWith(String.valueOf(punct))) { // Check if input contains a punctuation at the start
error.setText("Error: Word starts with an illegal character. Please try again!");
error.setForeground(Color.RED);
ta.append("");
}
}
}
I'm going to rephrase your problem a bit as clarification, please correct me if I'm misunderstanding.
You have a text field and a text area. You want a user to type a word into the text field and submit it. If that word starts with a number or punctuation, then indicate an error to the user. Otherwise, add it to the text area (on a new line) and the inner ArrayList.
To solve this problem, there are a couple things you'll need:
An ArrayList<String> that is a class member variable where you can store your words
An event handler that handles the button click.
The event handler should:
Parse the string from the text field (using getText(), as you already are).
Do the error checks you're already doing.
If neither of the error conditions are hit (so add an else clause for this), add the word to the text area (which you're already doing) and add it to the ArrayList.
Hopefully this helps you get a clearer idea of how to approach the problem. If not, please post a code sample of what you tried and what error you're specifically running into.
EDIT:
Here is some pseudocode for your if-else error-handling block of code, assuming you declare a new ArrayList to hold your words as a class member:
// as class member variable
List<String> wordList = new ArrayList<>();
// word handler code
if (str starts with a number) {
// handle error
} else if (str starts with punctuation) {
// handle error
} else {
ta.append(str + "\n");
wordList.add(str);
}

Having trouble clearing a text field when an improper character is entered

I am trying to retrieve the values from a JTextField on a keypress to do something if the values are integers and to clear the field if the values are not integers. Every time I try to retrieve the value, I am getting the value entered before that(if I enter 12 I get 1 back then if I enter 123 I get 12 back) and when I try to clear the field on an invalid character everything but the invalid character gets cleared?
public void setUpListeners()
{
JTextField jT [] = myV.getTextFields();
jT[0].addKeyListener(new KeyAdapter(){
public void keyTyped(KeyEvent e){
int id = e.getID();
if (id == KeyEvent.KEY_TYPED)
{
char c = e.getKeyChar();
try
{
//check if chars entered are numbers
int temp = Integer.parseInt(String.valueOf(c));
String tempS = jT[0].getText();
System.out.println(tempS);
}
catch(Exception ex)
{
jT[0].setText("");
System.out.println("Not an integer");
}
}
}
});
}
You could do the following:
public static boolean validateNumber(char num){
return (num >= '0' && num <='9');
}
And then use parameter KeyEvent "e":
if(!validateNumber(e.getKeyChar()))
e.consume();
And instead of using
public void keyTyped(KeyEvent e){
use
public void keyReleased(KeyEvent e){
I think you will get what you need, I hope I have helped you ;)
Swing components use Model-View-Controller (MVC) [software] design pattern / architecture. The model holds the data. For a JTextField the data is the text it displays. The default model for JTextField is PlainDocument, however JTextField code actually refers to the Document interface which PlainDocument implements.
Look at the code for method getText() in class JTextComponent (which is the superclass for JTextField) and you will see that it retrieves the text from the Document.
When you type a key in JTextField, the character gets passed to the Document. It would appear that your keyTyped() method is invoked before the character you typed reaches the Document, hence when you call getText() in your keyTyped() method, you're getting all the text apart from the last character you typed.
That's one of the reasons not to use a KeyListener in order to validate the text entered into a JTextField. The correct way is detailed in the question that tenorsax provided a link to in his comment to your question.
Apart from DocumentFilter or JFormattedTextField (or even InputVerifier), you can add an ActionListener to JTextField which will execute when you hit Enter in the JTextField. You will find many on-line examples of how to implement each one of these options, including the link provided in tenorsax comment.

How do I find out which textfield was not an integer

Basically I have created an applet that has three textfields one for each of the RGB values. I then created a try catch block to show a dialogue message if the user inputs a string. However, now I want it to find which textfield it was that had a string in it and set only that textfield to null so then they can type an integer, whilst also keeping the values of the two correct textfields.
So for example:
[255] [150] [cat]
step 2: [255] [150] [] (the string textfield should become null)
Code:
try{
if (e.getSource().equals (bttn))
{
as=T1.getText();
ag=T2.getText();
ab=T3.getText();
as=as.trim();
ag=ag.trim();
ab=ab.trim();
redColor= Integer.parseInt(as);
greenColor= Integer.parseInt(ag);
blueColor= Integer.parseInt(ab);
}
}
catch (NumberFormatException exception){
JOptionPane.showMessageDialog(null,"Integers Only","ERROR!",JOptionPane.WARNING_MESSAGE);
}
You have to split your code into tree parts, one for each field.
But this would result in redundant code. To avoid this, you should put the conversion part into a separate function which is called for each field.

How to limit user to input only numbers?

I am currently creating this java GUI that will ask the user to input 10 entries, then use the values to execte the next action.
I want only numbers or decimal point to be inputted inside such that it can only be a float value.
If it is not number or decimal point, it should prompt the user to input that specific entry again before the next action is executed.
How should I do it?
Wong,
not sure whether you are using Swing or not...
Ages ago I had the same problem and I solved it with creating a class RestrictedTextField extending JTextField. In the constructor I added a key listener (addKeyListener(new RestrictedKeyAdapter());)
private class RestrictedKeyAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
if (getText().equals("")) {
oldString = "";
return;
} else {
// if you cannot parse the string as an int, or float,
// then change the text to the text before (means: ignore
// the user input)
try {
if (type.equals("int")) {
int i = Integer.parseInt(getText());
oldString = getText();
} else if (type.equals("float")) {
float f = Float.parseFloat(getText());
oldString = getText();
} else {
// do nothing
}
} catch (NumberFormatException el) {
setText(oldString);
}
// if the text is identical to the initial text of this
// textfield paint it yellow. If the text was changed
// paint it red.
if (initialString.equals(getText())) {
setForeground(Color.YELLOW);
} else {
setForeground(Color.RED);
}
}
}
}
The idea is, that every time the user presses a key in the textfield (and releases it then), the text in the textfield is parsed. If the component should accept only floats for example then the component tries to parse it as an float (Float.parseFloat(..)). If this parsing is successful everything is fine. If the parsing fails (an NumberFormatException is thrown) then the old text is written back into the textfield (literally ignoring the user input).
I think you can add the KeyAdapter directly to the JTextField without creating a dedicated class for that, but with this solution you can remember the initial string and the old string.
you can play around with the code.. you can change the colour of the textfield if the input is valid or not (or like in my code snippet if the text is identical to the initial string).
one additional comment: I set the 'type' of the textfield in a variable with the name 'type', which is simply a String with the values "int", "float", etc.... a better solution would be here for example an enum of course...
I hope this is helpful...
timo
There are various options for what you would like to do. You can check here for one example of doing so. Another example could be to use Formatted TextFields, as shown here.
On the other hand, upon submission, you can try to parse the value to a float or double. If you get any exceptions, then, the value is not a number.
Lastly, you can use Regular Expressions. An expression such as ^\\d+(\\.\\d+)?$ should match any integer or floating point number.

DocumentListener slows down Document.setCharacterAttributes method?

this is my first question in this site, though is not the first time I enter to clear my doubts, awesome webpage. :)
I'm writing a java program that highlights code in a JTextPane and I'm changing the way highlights are done. I'm using a JTabbedPane to let the user edit more than one file at the same time and I used to perform document highlights using a Timer, now I've built a highlight queue that runs in a separate thread and implemented a DocumentListener that queues the documents as changes take place.
But I have a really big problem, if I add the document via DocumentListener, the Highlight process takes a really long time while if I add it in the main class by getting the document directly from the JTextPane, it takes just a few milliseconds.
I've performed multiple benchmarks in my code and found out that what takes so much time to be performed when the document is added from the DocumentListener is the method Document.setCharacterAttributes().
Here is the method that adds documents via DocumentListener:
// eventType: 0 - insertUpdate / 1- removeUpdate
private void queueChange(javax.swing.event.DocumentEvent e, int eventType){
StyledDocument doc = (StyledDocument) e.getDocument();
int changeLength = e.getLength();
int changeOffset = e.getOffset();
int length = doc.getLength();
String title = (String) doc.getProperty("title");
String text;
try {
text = doc.getText(0, length);
if (changeLength != 1) {
Element element = doc.getDefaultRootElement();
int startLn = element.getElement(element.getElementIndex(changeOffset)).getStartOffset();
int endLn = element.getElement(element.getElementIndex(changeOffset + changeLength)).getEndOffset() - 1;
Engine.addDocument(doc, startLn, endLn, title, text);
} else {
if(eventType == 1){
changeOffset = changeOffset - changeLength;
}
int startLn = text.lastIndexOf("\n", changeOffset) + 1;
int endLn = text.indexOf("\n", changeOffset);
if (endLn < 0) {
if (length != startLn) {
endLn = length;
Engine.addDocument(doc, startLn, endLn, title, text);
}
} else if (startLn != endLn && startLn < endLn) {
Engine.addDocument(doc, startLn, endLn, title, text);
}
}
} catch (BadLocationException ex) {
Engine.crashEngine();
}
}
If I add a document with 2k lines with this method, it takes ~1900 ms to highlight the whole document, while if I add the document to the highlight queue by using a caret listening method it takes ~500 ms.
Here's a part of the caret listening method that is used to highlight whole documents when they're loaded:
if (loadFile == true) {
isKey = false;
doc = edit[currentTab].Editor.getStyledDocument();
try {
Highlight.addDocument(doc, 0, doc.getLength(),
Scripts.getTitleAt(currentTab), doc.getText(0, doc.getLength()));
} catch (BadLocationException ex) {
ex.printStackTrace();
}
loadFile = false;
}
Note: the Highlight/Engine.addDocument() method has five parameters: (StyledDocument doc,int start, int end, String tabTitle, String docText). Start and end both indicate the region where highlighting is needed.
I will appreciate any help related to this problem cause I've been trying to solve it for a few days and I can't find anything similar on the Internet. :(
Btw, does anyone know the actual difference between Document.setCharacterAttributes and Document.setParagraphAttributes? :P
Maybe you have some kind of recursion in your code that is causing the problem. With the DocumentEvent you should only worry about additions and removals. You don't need to worry about changes since those are attribute changes.
Maybe you add some text which schedules the highlighting, but then when you change the attributes of the text you schedule another highllighting task.
You can try to set a flag indicating whether it's user changes or your API changes. In the beginning of the Engine.addDocument() set the flag to API state and reset it back after changes are done.
In your listener check the flag and skip changes from API.
You wrote " I use highlights the text by setting the character attributes of a portion of the Document, so the method is not inserting more text". I'm not sure it doesn't insert text. E.g. you have "it's a bold text piece" then you select the "bold" and change attributes to bold. Original element is separated and 3 new elements appear. I didn't test it but it might call insertUpdate() and removeUpdate()
does anyone know the actual difference between Document.setCharacterAttributes and Document.setParagraphAttributes?
There are paragraph and char attributes. Char attributes are font size, family, style, colors. Paragraph attributes are alignment, indentation, line spacing.
Actually paragraphs are char elements' parents.

Categories

Resources