Documentlistener Java, How to Prevent Empty String in Jtextbox

DocumentListener Java, How do I prevent empty string in JTextBox?

I'll make this an answer: I wouldn't use a DocumentListener for this purpose as it seems to me the wrong tool for the job. For one, it is continually listening and updating the results while the user is still entering data, data that is as yet incomplete, into the JTextField. Much better would be to use an ActionListener added to a JButton or to your JTextFields.

I suppose you could use a FocusListener, but even that concerns me since it is quite low-level.

Also: consider using an InputVerifier to validate your input.

Also: consider displaying your tabular data in a JTable where the 1st and 2nd columns are editable but the others are not.

Edit
I'm not sure if this is kosher, but it could work if you do your calculation from within the verifier. For example, updated for generality:

import javax.swing.*;

/**
* @see http://stackoverflow.com/a/11818183/522444
*/
public class VerifierEg {

private static final String ZERO = "0.0";
private JTextField field1 = new JTextField(ZERO, 5);
private JTextField field2 = new JTextField(ZERO, 5);
private JTextField resultField = new JTextField(ZERO, 10);

private void createAndShowGui() {
resultField.setEditable(false);
resultField.setFocusable(false);

JPanel mainPanel = new JPanel();
final JTextField[] fields = {field1, field2};

mainPanel.add(field1);
mainPanel.add(new JLabel(" x "));
mainPanel.add(field2);
mainPanel.add(new JLabel(" = "));
mainPanel.add(resultField);

for (JTextField field : fields) {
field.setInputVerifier(new MyInputVerifier(field));
}

JFrame frame = new JFrame("VerifierEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

private void calcProduct() {
double d1 = Double.parseDouble(field1.getText());
double d2 = Double.parseDouble(field2.getText());
double prod = d1 * d2;
resultField.setText(String.valueOf(prod));
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {

@Override
public void run() {
VerifierEg eg = new VerifierEg();
eg.createAndShowGui();
}
});
}

/**
* @see http://stackoverflow.com/a/11818946/230513
*/
private class MyInputVerifier extends InputVerifier {

private JTextField field;
private double value;

public MyInputVerifier(JTextField field) {
this.field = field;
}

@Override
public boolean shouldYieldFocus(JComponent input) {
if (verify(input)) {
field.setText(String.valueOf(value));
calcProduct();
return true;
} else {
field.setText(ZERO);
field.selectAll();
return false;
}

}

@Override
public boolean verify(JComponent input) {
try {
value = Double.parseDouble(field.getText());
return true;
} catch (NumberFormatException e) {
return false;
}
}
}
}

How to remove content of JTextField while DocumentListener is running?

In general, you don't -- you don't change the state of the Document while listening to it when using a DocumentListener. The two possible solutions that I know of:

  • From within your Listener, put the code that makes the changes that you wish to make within a Runnable and queue the Runnable onto the Swing event thread by calling SwingUtilities.invokeLater(yourRunnable). This is a shameless kludge
  • Much better: Don't use a DocumentListener but rather a DocumentFilter since this type of listener was geared towards making changes to the Document before the text is visualized within the component.

Unrelated side issue: your code shows a worrisome degree of coupling in that you try to change the text in a specific text component from within your listener. DocumentListeners should be fully agnostic of the text component whose document that they listen to, and in fact may be added to more than one Document.


A DocumentFilter has 3 methods that need to be overridden and do what you expect them to do: what you would expect them to do:

  • insertString: insert a String into the document
  • remove: removes text from the document
  • replace: replaces text in the document

What is more, these methods do their actions before the text component renders the changes to the document.

So within my method overrides, I extract the current document's text, and use the parameters to create what the new text will look like, for example for the replace method I did:

@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
StringBuilder sb = new StringBuilder(currentText);

String newText = sb.replace(offset, offset + length, text).toString();

I then do a boolean test on the newText to see if it is "good", and if so, call the super's method, here replace(...), passing in all the parameters. If not, if the newText fails the test, then I remove all the text from the document and show a JOptionPane.

So in this example, I use this as my test method:

private boolean isTextOk(String text) {
return !BAD_TEXTS.contains(text);
}

which tests to see if the text is any of the disallowed Strings, here "...", " ", "oops", "OOPS", but it could be any Strings that you desire. Again, if the text passes the text, call the super's method, else remove the text:

if (isTextOk(newText)) {
super.replace(fb, offset, length, text, attrs);
} else {
badText(fb);
}

Where badText(fb) does:

private void badText(FilterBypass fb) throws BadLocationException {
remove(fb, 0, fb.getDocument().getLength());
JOptionPane.showMessageDialog(null, "Don't do this!", "Bad Text Entered",
JOptionPane.WARNING_MESSAGE);
}

The whole example is:

import java.util.Arrays;
import java.util.List;
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
import javax.swing.text.PlainDocument;

@SuppressWarnings("serial")
public class ClearThreeDots extends JPanel {
private JTextField textField = new JTextField(40);

public ClearThreeDots() {
((PlainDocument) textField.getDocument()).setDocumentFilter(new MyDocFilter());
add(textField);
}

private static void createAndShowGui() {
ClearThreeDots mainPanel = new ClearThreeDots();

JFrame frame = new JFrame("Clear Three Dots");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}


class MyDocFilter extends DocumentFilter {
private static final List<String> BAD_TEXTS = Arrays.asList("...", " ", "oops", "OOPS");

@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
throws BadLocationException {
String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
StringBuilder sb = new StringBuilder(currentText);

String newText = sb.insert(offset, string).toString();

if (isTextOk(newText)) {
super.insertString(fb, offset, string, attr);
} else {
badText(fb);
}
}

@Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
StringBuilder sb = new StringBuilder(currentText);

String newText = sb.replace(offset, offset + length, "").toString();

if (isTextOk(newText)) {
super.remove(fb, offset, length);
} else {
badText(fb);
}

}

@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs)
throws BadLocationException {
String currentText = fb.getDocument().getText(0, fb.getDocument().getLength());
StringBuilder sb = new StringBuilder(currentText);

String newText = sb.replace(offset, offset + length, text).toString();

if (isTextOk(newText)) {
super.replace(fb, offset, length, text, attrs);
} else {
badText(fb);
}

}

private boolean isTextOk(String text) {
return !BAD_TEXTS.contains(text);
}

private void badText(FilterBypass fb) throws BadLocationException {
remove(fb, 0, fb.getDocument().getLength());
JOptionPane.showMessageDialog(null, "Don't do this!", "Bad Text Entered",
JOptionPane.WARNING_MESSAGE);
}

}

Java - Check if JTextField is empty or not

For that you need to add change listener (a DocumentListener which reacts for change in the text) for your JTextField, and within actionPerformed(), you need to update the loginButton to enabled/disabled depending on the whether the JTextfield is empty or not.

Below is what I found from this thread.

yourJTextField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
changed();
}
public void removeUpdate(DocumentEvent e) {
changed();
}
public void insertUpdate(DocumentEvent e) {
changed();
}

public void changed() {
if (yourJTextField.getText().equals("")){
loginButton.setEnabled(false);
}
else {
loginButton.setEnabled(true);
}

}
});

DocumentListener interfering with my JTextField

Right now your filter code just edits to make sure only integer digits are entered into the document.

After the insert you will also need to add an additional check to see if any data has been entered and then enable/disable the text field as required.

Here is an example that uses a DocumentListener to do this:

import java.awt.*;
import java.awt.event.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.*;

public class DataEntered implements DocumentListener
{
private JButton button;
private List<JTextField> textFields = new ArrayList<JTextField>();

public DataEntered(JButton button)
{
this.button = button;
}

public void addTextField(JTextField textField)
{
textFields.add( textField );
textField.getDocument().addDocumentListener( this );
}

public boolean isDataEntered()
{
for (JTextField textField : textFields)
{
if (textField.getText().trim().length() == 0)
return false;
}

return true;
}

@Override
public void insertUpdate(DocumentEvent e)
{
checkData();
}

@Override
public void removeUpdate(DocumentEvent e)
{
checkData();
}

@Override
public void changedUpdate(DocumentEvent e) {}

private void checkData()
{
button.setEnabled( isDataEntered() );
}

private static void createAndShowUI()
{
JButton submit = new JButton( "Submit" );
submit.setEnabled( false );

JTextField textField1 = new JTextField(10);
JTextField textField2 = new JTextField(10);

DataEntered de = new DataEntered( submit );
de.addTextField( textField1 );
de.addTextField( textField2 );

JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(textField1, BorderLayout.WEST);
frame.add(textField2, BorderLayout.EAST);
frame.add(submit, BorderLayout.SOUTH);
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}

public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}

The concept would be the same for a DocumentFilter. You need to do the check when you insert or remove text.

button doesn't turn disabled when textArea is empty

It's because you're not actually checking whether the text is empty; you're checking whether it's null. There's a difference between a String that's empty and a String that's null.

You need to be checking

if ("".equals(textArea.getText())) ...

if you want to check whether it's empty.

(You might also want to check for null.)

Value Change Listener to JTextField

Add a listener to the underlying Document, which is automatically created for you.

// Listen for changes in the text
textField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
warn();
}
public void removeUpdate(DocumentEvent e) {
warn();
}
public void insertUpdate(DocumentEvent e) {
warn();
}

public void warn() {
if (Integer.parseInt(textField.getText())<=0){
JOptionPane.showMessageDialog(null,
"Error: Please enter number bigger than 0", "Error Message",
JOptionPane.ERROR_MESSAGE);
}
}
});

keep jButton grey until jTextFields != null

You need to add listeners to detect when the user enters text. In order to have it register any change (and not just when the user hits Enter) you should attach a DocumentListener to the underlying document of each JTextField.

Then, have each listener call a function to do your check and update the JButton's enabled status accordingly.

Related



Related Topics



Leave a reply



Submit