开发者

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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜