In my program there are some GUI items (a JTable for example) which have Listener objects to listen for changes to the item's content when the content is changed by the program user. Then when the content is changed, it fires an event and that causes the program to update the content of the GUI by changing the content. However, of course when the program changes something, I don't want the GUI to react to that event. So what I do is I have a boolean called something like byuser and set it to true most of the time, and before the program changes the GUI, it sets byuser to false, and after it changes the GUI, it sets byuser to true again. And in the method called when the event is fired, I put a line which checks whether or not byuser is true, and does something only if byuser is true.
Anyway, that is how I do it. But I have a feeling that that is not the standard way to do it. What is the standard way of having a GUI object react to the user, but not to the program?
Joined: Oct 12, 2005
To be more specific about my question, I have a JTextField that has autocomplete function that I am trying to write. When I typed something in the JTextField, the program tried to change the text too and I got this message:
java.lang.IllegalStateException: Attempt to mutate in notification
Moving to another forum where we usually discuss GUIs
Joined: Oct 12, 2005
When the user clicks on an item in cList, that item is passed as a String to setInputText(String newText). userTextChange is set to false. Then .setText(String text) is called, which causes 2 events. The first event is removeUpdate(DocumentEvent e), and nothing happens, and the second event is insertUpdate(DocumentEvent e). When that is called, nothing happens because userTextChange is false. After that, userTextChange is set to true again.
When the user types something in input (the JTextField), insertUpdate(DocumentEvent e) is called, and because userTextChange is true, the findIndex() method is called, which chooses the index of a String from cList. Then cList scrolls to show the String. Then cList.setSelectedIndex(int index) is called. Here is where the problem is.
I expect the program-initiated selection of cList to trigger the valueChanged(ListSelectionEvent lse) event, which calls setInputText(String newText). Then userTextChange is changed to false, then the text is changed, but now that userTextChange is false, when removeUpdate and insertUpdate events occur, nothing happens.
That is what I expect, but I get an Exception which I described above arising in the setInputText(String newText) method.
Maybe what I need is a better way to change the text in input without causing the insertUpdate event.
you type something into the textfield, and during insertUpdate() you change the selected index of the list.
this change to the list triggers the listSelectionListener, which tries to set the text of the textfield,
so it errors because you're trying to change the text while it is still being modified (insertUpdate).
these few lines should fix it
add this as a class field
cLListener listListener = new cLListener();
add the two indicated lines in autoCompleteListener
The API of AbstractDocument has this explanation for the IllegalStateException thrown by the writeLock method:
"thrown on illegal lock attempt. If the document is implemented properly, this can only happen if a document listener attempts to mutate the document. This situation violates the bean event model where order of delivery is not guaranteed and all listeners should be notified before further mutations are allowed"
In my program, a document listener IS attempting to mutate the document (but indirectly).
So I think that my next step is to find a way to release the key in the AbstractDocument object so that the program can edit its text.
I know that when I click on an item in the JList, there is no problem. So I think that if the focus is off the JTextField, the key will be released. So I added the line
just before the setSelectedIndex(mLSIndex) line. I figured that if cList gets focused on, the user editing of the JTextField will come to an end and the key will be released. But that didn't work. I still got the same IllegalStateException.
just wrap setInptText(..) in a SwingUtilities.invokeLater
just curious, say you have a couple of places in your list
you want New Zealand, type N, so New York should appear in the textfield
how do you get New Zealand to appear
Joined: Oct 12, 2005
About the question of New York and New Zealand,
when you type in 'N' the program chooses one of the Strings that start with 'N'. That choice is based on several factors, one factor being how often each String was chosen in the past; the String chosen most in the past becomes the String that goes in the JTextField.
But suppose New York is the program-preferred String and you want to input New Zealand? The String chosen to go in the JTextField is based on the characters in the JTextField from the beginning to the position of the cursor. So when you type 'N', New York appears. Then when you type 'e', the cursor is after 'Ne' and New York is the String chosen. The same thing happens when you type in 'w' and space bar. But then when you type in 'Z', the only String beginning with 'New Z' is New Zealand, so that becomes the chosen String.
Another thing to do is, once New York is displayed, move the cursor to the right and then type 'Z' after 'New '.
If you want to enter 'New Zeal', type in 'New Z' and then move the cursor and use the delete key to delete 'and'.
Oh, yes, the cursor. I suspect that, when I figure out how to run this without Exceptions, I may have to think of a way to get the cursor in the position that it should be. Right now, input.requestFocus() makes the cursor go to the end of the String in input.