File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
The moose likes Swing / AWT / SWT and the fly likes altering a GUI object without triggering the listener Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login

Win a copy of Java Interview Guide this week in the Jobs Discussion forum!
JavaRanch » Java Forums » Java » Swing / AWT / SWT
Bookmark "altering a GUI object without triggering the listener" Watch "altering a GUI object without triggering the listener" New topic

altering a GUI object without triggering the listener

Kevin Tysen
Ranch Hand

Joined: Oct 12, 2005
Posts: 255
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?
Kevin Tysen
Ranch Hand

Joined: Oct 12, 2005
Posts: 255
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
What's that?
Rok Štelcer
Ranch Hand

Joined: Nov 03, 2009
Posts: 101

Kevin Tysen wrote:When I typed something in the JTextField, the program tried to change the text too

Perhaps you should just show the suggestions and not immediately change the input.

Anyhow, the best would be to share your code (a snip) with us ...


Campbell Ritchie

Joined: Oct 13, 2005
Posts: 46412
Moving to another forum where we usually discuss GUIs
Kevin Tysen
Ranch Hand

Joined: Oct 12, 2005
Posts: 255

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.
Michael Dunn
Ranch Hand

Joined: Jun 09, 2003
Posts: 4632
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();

change this
//cList.addListSelectionListener(new cLListener());

add the two indicated lines in autoCompleteListener
Kevin Tysen
Ranch Hand

Joined: Oct 12, 2005
Posts: 255
Removing the ListSelectionListener will keep my program from getting an Exception. However, I WANT the ListSelectionListener to change the text in the JTextField. The problem is (according to the printStackTrace) that when the Listener tries to change the text in the JTextField, it calls writeLock() method in the AbstractDocument object in the JTextField, which causes IllegalStateException because the writeLock is not available (probably because the cursor is still in the JTextField and it is in the middle of being edited by the user).

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.
Michael Dunn
Ranch Hand

Joined: Jun 09, 2003
Posts: 4632
> I WANT the ListSelectionListener to change the text in the JTextField.

just wrap setInptText(..) in a SwingUtilities.invokeLater

just curious, say you have a couple of places in your list
New York
New Zealand

you want New Zealand, type N, so New York should appear in the textfield
how do you get New Zealand to appear
Kevin Tysen
Ranch Hand

Joined: Oct 12, 2005
Posts: 255
Like this?

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.

Well, thanks for the help.
I agree. Here's the link:
subject: altering a GUI object without triggering the listener
It's not a secret anymore!