Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 14 of 14

Thread: ListDataListener get removed element

  1. #1
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default ListDataListener get removed element

    Hi there, this is my problem:

    I have a ListModel and a ListDataListener.
    When elements in the ListModel were removed the ListDataListener gets called and I get the indices of the removed interval.
    The problem is, I get the indices after the elements were already removed. So I have no way of knowing what elements those were!
    If I write the listener like this:
    	public void intervalRemoved(ListDataEvent e) {
    		Object thatWasRemoved = list.getElementAt(e.getIndex0());
    		System.out.println("Removed: "+thatWasRemoved);
    	}
    I do not get the correct result.

    So my question is, how would I know which element has been removed?

    Thank you all in advance.


  2. #2
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: ListDataListener get removed element

    That's a rough one... I'm not sure if there is a native way of doing it. However, if you can find in the source code where the fire method for the event handling, and if we can override that method, we might be able to "hack" it include the object in the event's payload.

    --- Update ---

    Ok, I have a hack for it, but it requires a bit of overriding.
    First, create a new class which extends ListDataEvent and just has additional payload:
    public class MyListDataEvent extends ListDataEvent {
    	private Object removedObject;
     
    	public ListDataEvent(Object source, int type, int index0, int index1, Object removed) {
    		super(source,type,index0,index1);
    		removedObject = removed;
    	}
     
    	public Object getRemovedObject() {
    		return removedObject;
    	}
    }
    Now we want to create a new fire method and override the remove method in our DefaultListModel. So if you are using the DefaultListModel (instead of extending it with another class), you would do:
    new DefaultListModel() {
    	protected void fireIntervalRemoved(Object source, int startIndex, int endIndex, Object removed) {
    		ListDataEvent event = new MyListDataEvent(source,ListDataEvent.INTERVAL_REMOVED,startIndex,endIndex,removed);
    		ListDataListener[] listeners = getListDataListeners();
    		for (int index = 0; index < listeners.length; index++)
    			listeners[index].intervalRemoved(event);
    	}
    	@Override
    	public Object remove(int index) {
    		Object rv = delegate.elementAt(index);
    		delegate.removeElementAt(index);
    		fireIntervalRemoved(this,index,index,rv);
    		return rv;
    	}
    	@Override
    	public void removeElementAt(int index) {
    		remove(index);
    	}
    	@Override
    	public boolean removeElement(Object obj) {
    		int index = indexOf(obj);
    		boolean rv = delegate.removeElement(obj);
    		if(index>=0 && rv)
    			fireIntervalRemoved(this,index,index,obj);
    		return rv;
    	}
    };
    We overrode the remove methods to use our new fireIntervalRemoved() method, which uses our new event.
    So your intervalRemoved() method would change to:
    public void intervalRemoved(ListDataEvent e) {
    	if(e instanceof MyListDataEvent) {
    		Object thatWasRemoved = ((MyListDataEvent)e).getRemovedObject();
    		System.out.println("Removed: "+thatWasRemoved);
    	}
    }

    That *should* "hack" it with the behavior, but I haven't tested it. Tell me if you come across any issues.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  3. #3
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    That hack would work. But I would prefer to not type-cast the ListDataEvent. What if I ever change my ListDataModel? (by the way, I do use a custom one)
    What if I dont work on the project anymore and someone else changes the ListDataModel without even knowing about this dependency?

    I just hope that there is some safer solution. But if there is none, then I will probably do it the way you suggested.

  4. #4
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: ListDataListener get removed element

    I'm not aware of any alternative solution, but I'm not some omniscient java god or anything, so there could be other ways, lol.
    The problem is that you need additional payload information, and the ListDataEvent doesn't provide any fields for additional payload. By the time the normal event is fired, the object has already been removed from the model's delegate vector. So unless you create some exact parallel vector, you've lost the object (I would not advise this, since trying to keep the two in parallel would be an incredible pain in the ass).
    As for changing the ListDataModel and other people modifying it in the future, the best suggestion I have for that is: make the dependency heavily documented.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  5. #5
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,318
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: ListDataListener get removed element

    Why do you need the removed elements? Can you deal with the removed elements in the portion of code that removes them rather than using a Listener?

  6. #6
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    The reason why I need them is quite complicated, but I try to make it simple and omit all unnecessary information.

    I have an application with a GUI. In this application the user can create 2 kinds of objects. Lets call them Interface and Class.
    Interfaces can have certain attributes which can be added / removed / edited through the use of the GUI.
    Classes have a number of Interfaces which they implement. For every attribute in every interface that a Class implements the class needs to have a cloned copy of that attribute for itself.

    My implementation for the Class is, that each time an Interface is added to the list of implemented Interfaces a ListDataListener is created by the class and registered at the Interface.
    When a new attribute is created for the Interface or an existing attribute is changed everything works fine.
    But when an attribute is deleted I dont know which one it was without iterating through all implemented Interfaces and all of their attributes as well as all cloned attributes to find the missing one.
    I figured it would be much more elegant and much less costly if the event would simply tell me what attribute was removed.

    I hope this was simple enough, its a quite complicated concept.

  7. #7
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,318
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: ListDataListener get removed element

    Complicated indeed...but I still don't understand why you need to know which attributes were removed. I ask this question in the off chance there may be a better way to design the app based upon the answer.

  8. #8
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    I need to know which attributes were removed in order to remove the cloned attributes.
    A class should not have any attributes which are not defined in one of the interfaces that it implements.

    So when an interface has one or more of its attributes removed the cloned copies must be removed from all classes that implement the interface.

  9. #9
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,318
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: ListDataListener get removed element

    I don't know what you mean by 'cloned attribute', but presuming it is a member of the same 'interface' as the attribute it is 'cloned' from, then a tree data structure sounds like something to consider. A 'class' is a grandparent, 'interface' a parent, 'attribute' a child, and 'cloned' attribute a grandchild (or some subset thereof). Anytime an attribute is removed, so are its cloned. Again, I'm not fully sure I follow the entire outline, but consider taking a step back and looking at the organization of your model - typically if I end up in a position such as this (in which a project relies on well built API which suddenly doesn't do it for me), I find it often best to step back and think hard about how the model is organized - often resulting in a different (and better (although better is often relative)) design.

  10. #10
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    Here, I made a code example, maybe this will help to illustrate the problem better:
    	private Map<Interface, ListDataListener> listenerMap;
     
    	public void addInterface(final Interface interF) {
    		for (Attribute atr : interF) {
    			addAttribute(atr.clone());
    		}
    		ListDataListener listener = new ListDataListener() {
     
    			Interface ownInterface = interF;
     
    			public void intervalRemoved(ListDataEvent e) {
    				// This is the part where the problem occurs!
    				Attribute atr = ownInterface.getElementAt(e.getIndex0());
    				removeCloneOfAttribute(atr);
    			}
     
    			public void intervalAdded(ListDataEvent e) {
    				Attribute atr = ownInterface.getElementAt(e.getIndex0());
    				addAttribute(atr.clone());
    			}
     
    			public void contentsChanged(ListDataEvent e) {
    				Attribute atr = ownInterface.getElementAt(e.getIndex0());
    				refreshCloneOfAttribute(atr);
    			}
    		};
    		interF.addListDataListener(listener);
    		listenerMap.put(interF, listener);
    	}
     
    	public void removeInterface(Interface interF) {
    		ListDataListener listener = listenerMap.get(interF);
    		interF.removeListDataListener(listener);
    		for (Attribute atr : interF) {
    			removeCloneOfAttribute(atr);
    		}
    	}
    I left out all the unnecessary bits of code. I hope the naming conventions are sufficient to show what is being done.

    I cant see right now how a tree structure would help in this case.

  11. #11
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,318
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: ListDataListener get removed element

    I believe I understand the original problem - the suggestion for using a Tree was not to directly address that problem. Rather, it was an indirect suggestion about how the 'model' of your program is designed. Whether or not a Tree is appropriate is up to you...the idea was to rethink your overall design. As the problem is stated - it sounds like your model is quite tightly integrated with you user interface - a reliance which causes issues like this, whose fixes can be rudimentary hacks which could introduce bugs and make later changes that much more difficult. A full redesign might sound like a lot of work, but is always worth considering.

    How I often design data models (rightly or wrongly) is by ignoring any UI altogether. Design the concrete classes of the model and any data structures which organize/manage these classes. One can also implement edit methods within the model which fire its own listener system. There are many reasons to recommend doing so - it makes the model readily customizable, easy to make changes without breaking things, independent of constraints like you ran into above, helps allow you to use the framework in another project, and helps make the code independent of the UI - allowing you to swap (or use multiple) UI if necessary (Swing, command line, JavaFX, J2EE, or J2ME).

    My 0.02. Sorry if this doesn't directly address your problem.

  12. #12
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    I guess I understand what you mean.
    You say I should not use the ListModel from the Swing framework and rather use my own Listener classes for inter-object communication within the data model. Then, when integrating the Data into a swing GUI I would wrap a ListModel around my initial design to make it compatible with Swing UI components.
    Is that correct?

    At first I tried it that way, but then realized that I was doing everything twice. It was almost like copied code that did the same thing but for different interfaces.
    I thought that by merging both together I could make the design more stable and readable instead of having everything doubled.

  13. #13
    Administrator copeg's Avatar
    Join Date
    Oct 2009
    Location
    US
    Posts
    5,318
    Thanks
    181
    Thanked 833 Times in 772 Posts
    Blog Entries
    5

    Default Re: ListDataListener get removed element

    Quote Originally Posted by Cornix View Post
    I guess I understand what you mean.
    You say I should not use the ListModel from the Swing framework and rather use my own Listener classes for inter-object communication within the data model. Then, when integrating the Data into a swing GUI I would wrap a ListModel around my initial design to make it compatible with Swing UI components.
    Is that correct?
    Pretty much.

    Quote Originally Posted by Cornix View Post
    At first I tried it that way, but then realized that I was doing everything twice. It was almost like copied code that did the same thing but for different interfaces.
    I thought that by merging both together I could make the design more stable and readable instead of having everything doubled.
    I'd prefer to use the word 'delegate' - the Swing models are used as delegates to access the underlying data model. You may need to implement a few more methods for the delegate, so in this sense it seems like more code is required, and it may seem this code is duplicated. For small programs this may not be necessary, but as programs grow and the data model gets more complex it can be a lot more flexible. Your mileage may vary

  14. #14
    Senior Member
    Join Date
    Jul 2013
    Location
    Europe
    Posts
    666
    Thanks
    0
    Thanked 121 Times in 105 Posts

    Default Re: ListDataListener get removed element

    Of course.
    Well thank you, I will think some more about this. Its a shame though that the swing ListDataListener has such constraints. It would not have been much for the developers to give us a chance to retrieve that data and I cant quite see a point for this limitation at the moment.
    But crying wont do me any good right now.

Similar Threads

  1. Replies: 0
    Last Post: September 7th, 2013, 06:09 AM
  2. watij clicking element help
    By bigblue002 in forum Member Introductions
    Replies: 2
    Last Post: May 1st, 2013, 12:38 AM
  3. [SOLVED] Creating an array with many of the same element?
    By ShamelessTeenie in forum Collections and Generics
    Replies: 2
    Last Post: April 9th, 2013, 11:28 AM
  4. get element of ArrayList.
    By gammaman in forum Collections and Generics
    Replies: 7
    Last Post: May 14th, 2012, 07:47 AM
  5. LinkedList outputs ONLY last element
    By hexwind in forum What's Wrong With My Code?
    Replies: 3
    Last Post: June 30th, 2011, 04:57 AM