In Java/Swing, is there a way to legally "attempt to mutate in notification"?
I was wondering if there is some sort of magic I can use to get around an IllegalStateException and allow a JTextField to "attempt to mutate in notification", or in other words to 开发者_如何学Cset its own text if its listener is triggered.
For your information, I am trying to program an auto-complete function which returns the most likely match in a range of 12 enums in response to a user's input in the JTextField.
Here is the code sample. You'll have to pardon my clumsy algorithm which creaks out enum results. I've highlighted the code which produces the exception with a comment:
jtfElement1.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
String s = jtfElement1.getText();
int[] attributes = new int[13];
// iterate through each enum
for (BaseEnumAttributes b: BaseEnumAttributes.values()) {
// iterate through the length of the current text in jtfElement1
for (int i = 0; i < s.length(); i++) {
if (s.length() <= b.toString().length()) {
if (b.toString().charAt(i) == s.charAt(i)) {
// increase the number of "hits" noted for that enum
attributes[b.ordinal()] = attributes[b.ordinal()] + 1;
}
}
}
}
int priorC = 0;
int rightC = 0;
// iterate through the "array" of enums to find the highest score
for (int j = 0; j < attributes.length; j++) {
if (attributes[j] > priorC) {
priorC = attributes[j];
rightC = j;
}
}
if (!s.equals("")) {
// assign to b the Enum corresponding to the "array" with highest score
BaseEnumAttributes b = BaseEnumAttributes.values()[rightC];
iController.updateInputElement1String(b.toString());
// THIS TRIGGERS EXCEPTION
jtfElement1.setText(b.toString());
}
}
});
You are probably better off using a document filter or a custom document.
What are other listeners expected to see if the document doesn't stay the same during event dispatch?
Use SwingUtilities.invokeLater() placing all the modifications there
Maybe you can delay the setText() with a Thread to run after caretUpdate() has terminated.
i'm found on the same problem but i found an easy solution:
lock the caretUpdate() by a boolean if(false) while u'r setting the text to the jTextField than unlock it after . . something like this:
boolean caret = true;
private void listValueChanged(javax.swing.event.ListSelectionEvent evt) { caret = false; name.setText((String)list.getSelectedValue()); caret = true; }
private void nameCaretUpdate(javax.swing.event.CaretEvent evt) {
if(caret){
model = new DefaultListModel();
this.fillList(name.getText());
list.setModel(model);
}
}
Create a custom Document and override insertString( )
filenameText = new JTextField(new FilenameDocument(), "", 0);
...
/**
* document which adds .xml extension if not specified
*
*/
private class FilenameDocument extends PlainDocument {
@Override
public void insertString(int offset, String insertedText, AttributeSet set)
throws BadLocationException {
if (offset == 0) {
insertedText = insertedText.trim( );
}
super.insertString(offset, insertedText, set);
if (filenameText != null) {
final int caretPos = filenameText.getCaretPosition();
String text = filenameText.getText().trim();
if (text.indexOf('.') == -1) {
filenameText.setText(text + ".xml");
filenameText.setCaretPosition(caretPos);
}
}
}
}
Note that calling setText will result in a recursive call to insertString( ), so make sure you have a stopping condition.
I'm surprised no one has answered this, but would'nt you have been better off implementing an editable JSpinner with a SpinnerListModel?
精彩评论