Using HashSet to check if a key is pressed - java

I have recently been writing a program that has a:
public static Set<Character> pressed = new HashSet<Character>();
Now the Set "pressed" is added to like this:
public void keyPressed(KeyEvent e) {
pressed.add(e.getKeyChar());
}
public void keyReleased(KeyEvent e) {
pressed.remove(e.getKeyChar());
}
public void keyTyped(KeyEvent e) {
//System.out.println("keyTyped");
}
Now if I wanted to do something like
pressed.contains(x);
Where x was a key on the keyboard, how would I do that. I have tried
pressed.contains(KeyEvent.VK_UP);
However it seems that even when I am pressing the up arrow key, the Set "pressed" does not contains the event VK_UP. All I need to know is how to figure out what to enter into the .contains parameter to check if it is in the Set pressed.

Where you do
public static Set<Character> pressed = new HashSet<Character>();
---
pressed.add(e.getKeyChar());
you should be doing
public static Set<Integer> pressed = new HashSet<>();
...
pressed.add(e.getKeyCode());
^^^^
Also make the analogous change to the remove code.
The key code is the raw keyboard code that you are comparing to, not the character assigned to the key (not all keys have characters assigned).

Related

Boolean in Java condition

I have an issue, I have a method which is an action performed. If the checkbox is ticked then additional fields become available. If not ticked then they are greyed out. So basically what I want is to add to this method. I have a first condition and now need to add a second condition to it. I pasted the code snippet below, basically what I need is to put it into an if else, but I get some errors. Any advise is much appreciated.
public void actionPerformed(ActionEvent e) {
boolean sel = _useSSL.isSelected();
_port.setUseSSL(sel);
_keystore.setEnabled(sel);
_passphrase.setEnabled(sel);
L_KEYSTORE.setEnabled(sel);
L_PASSPHRASE.setEnabled(sel);
}
Above is the working method, now I need to add in if _truststore.isSelected(); then execute something else.
How can I add this second Boolean condition to the method?
I think you can do it by building a method per boolean and binding them to one "action performed" method like this:
public void actionPerformedForUseSSL(boolean useSSL) {
_port.setUseSSL(useSSL);
_keystore.setEnabled(useSSL);
_passphrase.setEnabled(useSSL);
L_KEYSTORE.setEnabled(useSSL);
L_PASSPHRASE.setEnabled(useSSL);
}
public void actionPerformedForTrustStore(boolean trustStore) {
_port.setTrustStore(trustStore);
_a.setEnabled(trustStore);
_b.setEnabled(trustStore);
_c.setEnabled(trustStore);
}
//Fire this when action performed
public void actionPerformed() {
boolean sel = _useSSL.isSelected();
boolean trust = _trustStore.isSelected();
actionPerformedForUseSSL(sel);
if(trust) {
actionPerformedForTrustStore(trust);
}
}
Add or remove or mix any fields with this structure easily.
You can use it just like you have used 'sel' in "actionPerfomed" method like this:
public void actionPerformed(ActionEvent e) {
boolean sel = _useSSL.isSelected();
_port.setUseSSL(sel);
_keystore.setEnabled(sel);
_passphrase.setEnabled(sel);
L_KEYSTORE.setEnabled(sel);
L_PASSPHRASE.setEnabled(sel);
boolean trus = _truststore.isSelected();
//Use trus for the other things
}
You can use the following piece of code:
public void actionPerformed(ActionEvent e) {
boolean sel = _useSSL.isSelected();
_port.setUseSSL(sel);
_keystore.setEnabled(sel);
_passphrase.setEnabled(sel);
L_KEYSTORE.setEnabled(sel);
L_PASSPHRASE.setEnabled(sel);
boolean selOther= _truststore.isSelected();
if(selOther){
//perform task if the _truststore is selected
}
}

How to get index of an object with documentListener?

I have 2 lists displayed vertically in a JFrame. Lets say list A is an ArrayList<CustomTexField> and list B is an ArrayList<JLabel>.
I want to "update" the elements of list B that matches the same index of elements inside list A with the value from the CustomTextField.
I've tried adding document listener, but don't know how to calculate the index.
#Override
public void insertUpdate(DocumentEvent e) {
try {
listB().get(INDEX).setText(e.getDocument().getText(0, e.getDocument().getLength()) + "");
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
I have also created a method inside CustomTexField class that saves the index when its created but don't know how to 'read' it from e.getDocument()
EDIT: UPDATED TITLE
If you're just trying to get the index of an item in an arraylist, you can just use the indexOf method.
int indexOfItem = arrayList.indexOf(itemIWant)
This is just how I interpreted your question but I would love clarification.
EDIT: If you're trying to get the object attached to the DocumentListener, you can check out this question: how to find source component that generated a DocumentEvent
Basically, if you have a DocumentListener for each CustomTextField, you can use the putProperty method described in the link to attach itself to it. From there, you can use getProperty(item) to find the item. You can do something similar with the index if you want but I believe that since you have an index field in your definition of CustomTextField, just attaching the CustomTextField with the DocumentListener will be enough.
//sometime on initalization of the lists
for(CustomTextField field: listA):
field.getDocument().putProperty("owner", field);
...
#Override
public void insertUpdate(DocumentEvent e) {
try {
CustomTextField field = e.getDocument().getProperty("owner");
int index = field.getIndex(); //assuming you have a getter method
listB().get(index).setText(listA.get(index).getText());
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
I would store all of your CustomTextFields in a Map<String, Integer> where the key is the name of the CustomTextField and the value is a unique identifier. Then I would have all of your Labels in another Map<Integer, Label> where the key is a unique identifier that corresponds to the unique identifier that matches a CustomTextField.
Now in your insertUpdate() you know which CustomTextField that's getting updated, so get it's unique identifier like:
int id = ctfMap.get(customTextField.getName());
Take this id and get your Label like this:
JLabel label = lblMap.get(id);
Set the label's text:
label.setText = customTextField.getText();
I found an answer here . I also added focusListener to the CustomTextFields so when overriding focusGained method I can get the Object where the event where called from and cast it to my custom class.
private class ListenForDoc implements DocumentListener, FocusListener{
int index;
#Override
public void insertUpdate(DocumentEvent e) {
try {
listB().get(index).setText(e.getDocument().getText(0, e.getDocument().getLength()));
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
#Override
public void removeUpdate(DocumentEvent e) {
//TO DO
}
#Override
public void changedUpdate(DocumentEvent e) {}
#Override
public void focusGained(FocusEvent e) {
Object o = e.getSource();
if(o instanceof CustomTextField) {
index = ((CustomTextField)o).getIndex();
}
else{
//HandleError
}
}
#Override
public void focusLost(FocusEvent e) {
// TODO Auto-generated method stub
}
}

German characters in JTextField

I'm working on a Java application for people learning German, and I have run into a problem with the special characters of this language. I want to make a subclass of JTextField that will interpret ALT + a as ä, ALT + o as ö and so on, while behaving as usual for all ASCII characters.
My attempts so far:
public class GermanTextField extends JTextField implements KeyListener{
public GermanTextField() {
init();
}
// other constructors ...
private void init() {
addKeyListener(this);
}
public void keyPressed(KeyEvent arg0) {}
public void keyReleased(KeyEvent arg0) {}
public void keyTyped(KeyEvent evt) {
if(evt.getKeyChar() == 'o' && evt.isAltGraphDown()){
setText(getText() + "ö");
evt.consume();
}
}
}
Code above does not work (GermanTextField behaves like standard JTextField), and when I print evt.getKeyChar() to console this is what I get:
?
?
?
?
This may be due to my own language, because ALT + o produces ó on my system. Of course I could have done it like that:
public void keyTyped(KeyEvent evt) {
if(evt.getKeyChar() == 'ó'){
setText(getText() + "ö");
evt.consume();
}
}
But it probably won't work on any systems other than Polish.
My question is: is there any solution to this problem that will behave as expected on systems with different language settings?
Full solution to this problem, based on MvGs answer:
package daswort.gui;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JTextField;
public class GermanTextField extends JTextField implements KeyListener{
private Map<Integer, String> transform =
new HashMap<Integer, String>();
public GermanTextField() {
init();
}
public GermanTextField(int columns) {
super(columns);
init();
}
public GermanTextField(String text, int columns) {
super(text, columns);
init();
}
public GermanTextField(String text) {
super(text);
init();
}
private void init() {
transform.put(KeyEvent.VK_A, "äÄ");
transform.put(KeyEvent.VK_U, "üÜ");
transform.put(KeyEvent.VK_O, "öÖ");
addKeyListener(this);
}
public void keyPressed(KeyEvent evt) {
if(evt.isAltGraphDown()){
String umlaut = transform.get(evt.getKeyCode());
if(umlaut != null){
int idx = evt.isShiftDown() ? 1 : 0;
setText(getText() + umlaut.charAt(idx));
}
}
}
public void keyReleased(KeyEvent arg0) {}
public void keyTyped(KeyEvent evt) {
if(evt.isAltGraphDown()){
evt.consume();
}
}
}
To identify key events independent of the current locale, don't use getKeyChar. Instead, use isKeyCode() to identify the key independent of the character associated with it. Like this:
if (evt.getKeyCode() == KeyEvent.VK_O && evt.isAltGraphDown())
This should match Alt Gr + O on any keyboard layout.
This may be due to my own language, because ALT + o produces ó on my system. Of course I could have done it like that:
use DocumentFilter for JTextComponents
But it probably won't work on any systems other than polish.
My question is: is there any solution to this problem that will behave as expected on systems with different language settings?
no there aren't,
to hope that all PC have got imputed correct value for Locale in Native OS (wrong decision)
you are able to wrote any Unicode Chars by using ALT and numbers
most safiest is only the setting by useraction about the Locale, then you can to create an array of chars for concrete Locale (own Encode Page)
The problem is that JTextField uses a different default font than JTextArea. I had the same problem in an application I wrote that had to support multi-languages.
The reason for your problem is that JTextField is normally used to show a mono-spaced font, such as Courier New. Normally Java contains no additional mappings for a mono-spaced graphical font to display Kanji.
The fix you have works, because there is no font named "123", so the default is taken (dialog). The "dialog" font is internally mapped to a font family in the font.properties file of your platform. This will be the same font that JTextField uses.
I have the following fix, to ensure that the same font definition is used in ALL graphical components. You can also find the specific key for JTextField and change it. This way you don't have to worry about the fonts of any component, they will be initialized with dialog.
Please enter the following code inside your class containing the JTextField.
Object fontDefinition = new UIDefaults.ProxyLazyValue("javax.swing.plaf.FontUIResource", null, new Obje
java.util.Enumeration keys = UIManager.getDefaults().keys();
while (keys.hasMoreElements()) {
Object key = keys.nextElement();
Object value = UIManager.get(key);
if (value instanceof javax.swing.plaf.FontUIResource) {
UIManager.put(key, fontDefinition);
}
}
Hope this helps.

Save and Delete buttons not working

I want to save whatever I write in a textfield and delete the line the program finds after clicked on search button. why doesn't it work? Here are my two buttons:
private class dDelete implements ActionListener {
public void actionPerformed (ActionEvent e) {
HM.remove((String)result.getText());
}
}
private class sSave implements ActionListener {
public void actionPerformed (ActionEvent e) {
Set <String> ISet = HM.keySet();
Iterator itr = ISet.iterator();
String tuple = "";
java.io.File iwrite = new java.io.File("c:\\temp\\savetest.txt");
if (iwrite.exists()){
System.out.println("The file exists");
System.exit(0);
}
java.io.PrintWriter output = null;
try {
output = new java.io.PrintWriter(iwrite);
} catch(Exception ex) {
ex.printStackTrace();
}
while (itr.hasNext()) {
String Keys = (String)itr.next();
String val = HM.get(Keys);
tuple = Keys + " " + val;
output.print(tuple);
}
}
}
You should close your output writer output.close() that could be why.
You are not showing what you are adding to the set HM so hard to tell if the remove will work. Check the return value of the call to HM.remove and you will see if it succeeds, else you are using the wrong keys (not using the same/equal one when adding as removing).
Other than that I would recommend iterating over the entrySet when you need both the key and the value (HM.entrySet()).
Also rename your classes and variables according to Java naming conventions (classes start with a capital letter, instance variables shouldn't etc). For more info. see the Java naming conventions.

Value Change Listener to JTextField

I want the message box to appear immediately after the user changes the value in the textfield. Currently, I need to hit the enter key to get the message box to pop out. Is there anything wrong with my code?
textField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent e) {
if (Integer.parseInt(textField.getText())<=0){
JOptionPane.showMessageDialog(null,
"Error: Please enter number bigger than 0", "Error Message",
JOptionPane.ERROR_MESSAGE);
}
}
}
Any help would be appreciated!
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);
}
}
});
The usual answer to this is "use a DocumentListener". However, I always find that interface cumbersome. Truthfully the interface is over-engineered. It has three methods, for insertion, removal, and replacement of text, when it only needs one method: replacement. (An insertion can be viewed as a replacement of no text with some text, and a removal can be viewed as a replacement of some text with no text.)
Usually all you want is to know is when the text in the box has changed, so a typical DocumentListener implementation has the three methods calling one method.
Therefore I made the following utility method, which lets you use a simpler ChangeListener rather than a DocumentListener. (It uses Java 8's lambda syntax, but you can adapt it for old Java if needed.)
/**
* Installs a listener to receive notification when the text of any
* {#code JTextComponent} is changed. Internally, it installs a
* {#link DocumentListener} on the text component's {#link Document},
* and a {#link PropertyChangeListener} on the text component to detect
* if the {#code Document} itself is replaced.
*
* #param text any text component, such as a {#link JTextField}
* or {#link JTextArea}
* #param changeListener a listener to receieve {#link ChangeEvent}s
* when the text is changed; the source object for the events
* will be the text component
* #throws NullPointerException if either parameter is null
*/
public static void addChangeListener(JTextComponent text, ChangeListener changeListener) {
Objects.requireNonNull(text);
Objects.requireNonNull(changeListener);
DocumentListener dl = new DocumentListener() {
private int lastChange = 0, lastNotifiedChange = 0;
#Override
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
#Override
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
lastChange++;
SwingUtilities.invokeLater(() -> {
if (lastNotifiedChange != lastChange) {
lastNotifiedChange = lastChange;
changeListener.stateChanged(new ChangeEvent(text));
}
});
}
};
text.addPropertyChangeListener("document", (PropertyChangeEvent e) -> {
Document d1 = (Document)e.getOldValue();
Document d2 = (Document)e.getNewValue();
if (d1 != null) d1.removeDocumentListener(dl);
if (d2 != null) d2.addDocumentListener(dl);
dl.changedUpdate(null);
});
Document d = text.getDocument();
if (d != null) d.addDocumentListener(dl);
}
Unlike with adding a listener directly to the document, this handles the (uncommon) case that you install a new document object on a text component. Additionally, it works around the problem mentioned in Jean-Marc Astesana's answer, where the document sometimes fires more events than it needs to.
Anyway, this method lets you replace annoying code which looks like this:
someTextBox.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
doSomething();
}
#Override
public void removeUpdate(DocumentEvent e) {
doSomething();
}
#Override
public void changedUpdate(DocumentEvent e) {
doSomething();
}
});
With:
addChangeListener(someTextBox, e -> doSomething());
Code released to public domain. Have fun!
Just create an interface that extends DocumentListener and implements all DocumentListener methods:
#FunctionalInterface
public interface SimpleDocumentListener extends DocumentListener {
void update(DocumentEvent e);
#Override
default void insertUpdate(DocumentEvent e) {
update(e);
}
#Override
default void removeUpdate(DocumentEvent e) {
update(e);
}
#Override
default void changedUpdate(DocumentEvent e) {
update(e);
}
}
and then:
jTextField.getDocument().addDocumentListener(new SimpleDocumentListener() {
#Override
public void update(DocumentEvent e) {
// Your code here
}
});
or you can even use lambda expression:
jTextField.getDocument().addDocumentListener((SimpleDocumentListener) e -> {
// Your code here
});
Be aware that when the user modify the field, the DocumentListener can, sometime, receive two events. For instance if the user selects the whole field content, then press a key, you'll receive a removeUpdate (all the content is remove) and an insertUpdate.
In your case, I don't think it is a problem but, generally speaking, it is.
Unfortunately, it seems there's no way to track the content of the textField without subclassing JTextField.
Here is the code of a class that provide a "text" property :
package net.yapbam.gui.widget;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
/** A JTextField with a property that maps its text.
* <br>I've found no way to track efficiently the modifications of the text of a JTextField ... so I developed this widget.
* <br>DocumentListeners are intended to do it, unfortunately, when a text is replace in a field, the listener receive two events:<ol>
* <li>One when the replaced text is removed.</li>
* <li>One when the replacing text is inserted</li>
* </ul>
* The first event is ... simply absolutely misleading, it corresponds to a value that the text never had.
* <br>Anoter problem with DocumentListener is that you can't modify the text into it (it throws IllegalStateException).
* <br><br>Another way was to use KeyListeners ... but some key events are throw a long time (probably the key auto-repeat interval)
* after the key was released. And others events (for example a click on an OK button) may occurs before the listener is informed of the change.
* <br><br>This widget guarantees that no "ghost" property change is thrown !
* #author Jean-Marc Astesana
* <BR>License : GPL v3
*/
public class CoolJTextField extends JTextField {
private static final long serialVersionUID = 1L;
public static final String TEXT_PROPERTY = "text";
public CoolJTextField() {
this(0);
}
public CoolJTextField(int nbColumns) {
super("", nbColumns);
this.setDocument(new MyDocument());
}
#SuppressWarnings("serial")
private class MyDocument extends PlainDocument {
private boolean ignoreEvents = false;
#Override
public void replace(int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
String oldValue = CoolJTextField.this.getText();
this.ignoreEvents = true;
super.replace(offset, length, text, attrs);
this.ignoreEvents = false;
String newValue = CoolJTextField.this.getText();
if (!oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
}
#Override
public void remove(int offs, int len) throws BadLocationException {
String oldValue = CoolJTextField.this.getText();
super.remove(offs, len);
String newValue = CoolJTextField.this.getText();
if (!ignoreEvents && !oldValue.equals(newValue)) CoolJTextField.this.firePropertyChange(TEXT_PROPERTY, oldValue, newValue);
}
}
I know this relates to a really old problem, however, it caused me some problems too. As kleopatra responded in a comment above, I solved the problem with a JFormattedTextField. However, the solution requires a bit more work, but is neater.
The JFormattedTextField doesn't by default trigger a property change after every text changes in the field. The default constructor of JFormattedTextField does not create a formatter.
However, to do what the OP suggested, you need to use a formatter which will invoke the commitEdit() method after each valid edit of the field. The commitEdit() method is what triggers the property change from what I can see and without the formatter, this is triggered by default on a focus change or when the enter key is pressed.
See http://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html#value for more details.
Create a default formatter (DefaultFormatter) object to be passed to the JFormattedTextField either via its constructor or a setter method. One method of the default formatter is setCommitsOnValidEdit(boolean commit), which sets the formatter to trigger the commitEdit() method every time the text is changed. This can then be picked up using a PropertyChangeListener and the propertyChange() method.
An elegant way is to add the listener to the caret position, because it changes every time something is typed/deleted, then just compare old value with current one.
String oldVal = ""; // empty string or default value
JTextField tf = new JTextField(oldVal);
tf.addCaretListener(e -> {
String currentVal = tf.getText();
if(!currentVal.equals(oldVal)) {
oldVal = currentVal;
System.out.println("Change"); // do something
}
});
(This event is also being triggered every time a user just clicks into a TextField).
textBoxName.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
onChange();
}
#Override
public void removeUpdate(DocumentEvent e) {
onChange();
}
#Override
public void changedUpdate(DocumentEvent e) {
onChange();
}
});
But I would not just parse anything the user (maybe on accident) touches on his keyboard into an Integer. You should catch any Exceptions thrown and make sure the JTextField is not empty.
If we use runnable method SwingUtilities.invokeLater() while using Document listener application is getting stuck sometimes and taking time to update the result(As per my experiment). Instead of that we can also use KeyReleased event for text field change listener as mentioned here.
usernameTextField.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent e) {
JTextField textField = (JTextField) e.getSource();
String text = textField.getText();
textField.setText(text.toUpperCase());
}
});
it was the update version of Codemwnci. his code is quite fine and works great except the error message. To avoid error you must change the condition statement.
// 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 (textField.getText().length()>0){
JOptionPane.showMessageDialog(null,
"Error: Please enter number bigger than 0", "Error Massage",
JOptionPane.ERROR_MESSAGE);
}
}
});
You can use even "MouseExited" to control.
example:
private void jtSoMauMouseExited(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
try {
if (Integer.parseInt(jtSoMau.getText()) > 1) {
//auto update field
SoMau = Integer.parseInt(jtSoMau.getText());
int result = SoMau / 5;
jtSoBlockQuan.setText(String.valueOf(result));
}
} catch (Exception e) {
}
}
Use a KeyListener (which triggers on any key) rather than the ActionListener (which triggers on enter)
DocumentFilter ? It gives you the ability to manipulate.
[ http://www.java2s.com/Tutorial/Java/0240__Swing/FormatJTextFieldstexttouppercase.htm ]
Sorry. J am using Jython (Python in Java) - but easy to understand
# python style
# upper chars [ text.upper() ]
class myComboBoxEditorDocumentFilter( DocumentFilter ):
def __init__(self,jtext):
self._jtext = jtext
def insertString(self,FilterBypass_fb, offset, text, AttributeSet_attrs):
txt = self._jtext.getText()
print('DocumentFilter-insertString:',offset,text,'old:',txt)
FilterBypass_fb.insertString(offset, text.upper(), AttributeSet_attrs)
def replace(self,FilterBypass_fb, offset, length, text, AttributeSet_attrs):
txt = self._jtext.getText()
print('DocumentFilter-replace:',offset, length, text,'old:',txt)
FilterBypass_fb.replace(offset, length, text.upper(), AttributeSet_attrs)
def remove(self,FilterBypass_fb, offset, length):
txt = self._jtext.getText()
print('DocumentFilter-remove:',offset, length, 'old:',txt)
FilterBypass_fb.remove(offset, length)
// (java style ~example for ComboBox-jTextField)
cb = new ComboBox();
cb.setEditable( true );
cbEditor = cb.getEditor();
cbEditorComp = cbEditor.getEditorComponent();
cbEditorComp.getDocument().setDocumentFilter(new myComboBoxEditorDocumentFilter(cbEditorComp));
I am brand new to WindowBuilder, and, in fact, just getting back into Java after a few years, but I implemented "something", then thought I'd look it up and came across this thread.
I'm in the middle of testing this, so, based on being new to all this, I'm sure I must be missing something.
Here's what I did, where "runTxt" is a textbox and "runName" is a data member of the class:
public void focusGained(FocusEvent e) {
if (e.getSource() == runTxt) {
System.out.println("runTxt got focus");
runTxt.selectAll();
}
}
public void focusLost(FocusEvent e) {
if (e.getSource() == runTxt) {
System.out.println("runTxt lost focus");
if(!runTxt.getText().equals(runName))runName= runTxt.getText();
System.out.println("runText.getText()= " + runTxt.getText() + "; runName= " + runName);
}
}
Seems a lot simpler than what's here so far, and seems to be working, but, since I'm in the middle of writing this, I'd appreciate hearing of any overlooked gotchas. Is it an issue that the user could enter & leave the textbox w/o making a change? I think all you've done is an unnecessary assignment.
Here is a Kotlin port of #Boann's answer, which is a great solution that has been working well for me.
import java.beans.*
import javax.swing.*
import javax.swing.event.*
import javax.swing.text.*
/**
* Installs a listener to receive notification when the text of this
* [JTextComponent] is changed. Internally, it installs a [DocumentListener] on the
* text component's [Document], and a [PropertyChangeListener] on the text component
* to detect if the `Document` itself is replaced.
*
* #param changeListener a listener to receive [ChangeEvent]s when the text is changed;
* the source object for the events will be the text component
*/
fun JTextComponent.addChangeListener(changeListener: ChangeListener) {
val dl: DocumentListener = object : DocumentListener {
private var lastChange = 0
private var lastNotifiedChange = 0
override fun insertUpdate(e: DocumentEvent) = changedUpdate(e)
override fun removeUpdate(e: DocumentEvent) = changedUpdate(e)
override fun changedUpdate(e: DocumentEvent) {
lastChange++
SwingUtilities.invokeLater {
if (lastNotifiedChange != lastChange) {
lastNotifiedChange = lastChange
changeListener.stateChanged(ChangeEvent(this))
}
}
}
}
addPropertyChangeListener("document") { e: PropertyChangeEvent ->
(e.oldValue as? Document)?.removeDocumentListener(dl)
(e.newValue as? Document)?.addDocumentListener(dl)
dl.changedUpdate(null)
}
document?.addDocumentListener(dl)
}
You can use it on any text component as follows:
myTextField.addChangeListener { event -> myEventHandler(event) }
Like his code, also public domain.

Categories