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 documentremove
: removes text from the documentreplace
: 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
Calling Jmx Mbean Method from a Shell Script
Preparedstatement with Statement.Return_Generated_Keys
How to Properly Use Java Executor
Why Is Maven Downloading the Maven-Metadata.Xml Every Time
Correct Use of Flush() in JPA/Hibernate
What Is the Default Max Heap Size (-Xmx) in Java 8
How to Add Shapes on Javafx Linechart
Loading a Text File into a Textarea
Jackson Overcoming Underscores in Favor of Camel-Case
What Hashing Function Does Java Use to Implement Hashtable Class
Injecting Beans into a Class Outside the Spring Managed Context
Generate Java Classes from .Xsd Files...
How to Clear or Empty a Stringbuilder
Difference Between @Onetomany and @Elementcollection
Difference Between Hashset and Hashmap