I want a javax.swing.ListModel be shared among multiple javax.swing.ComboBoxModels.
With the following code , when I select an item from the JComboBox,in a running program through the view, the JComboBox always shows the first item as selected.
public class DelegatedComboBoxModel<T> extends AbstractListModel<T> implements
ComboBoxModel<T> {
protected ListModel<T> listModel;
protected Object selectedObject;
ListDataListener listDataChangeDelegater = new ListDataListener() {
#Override
public void intervalRemoved(ListDataEvent e) {
fireIntervalRemoved(DelegatedComboBoxModel.this, e.getIndex0(),
e.getIndex1());
}
#Override
public void intervalAdded(ListDataEvent e) {
fireIntervalAdded(DelegatedComboBoxModel.this, e.getIndex0(),
e.getIndex1());
}
#Override
public void contentsChanged(ListDataEvent e) {
fireContentsChanged(DelegatedComboBoxModel.this, e.getIndex0(),
e.getIndex1());
}
};
public DelegatedComboBoxModel(ListModel<T> listModel) {
// DefaultComboBoxModel<E>
this.listModel = listModel;
if (listModel.getSize() > 0) {
selectedObject = listModel.getElementAt(0);
}
listModel.addListDataListener(listDataChangeDelegater);
}
#Override
public T getElementAt(int index) {
if (index >= 0 && index < listModel.getSize())
return listModel.getElementAt(index);
else
return null;
}
#Override
public int getSize() {
return listModel.getSize();
}
#Override
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals(anObject))
|| selectedObject == null && anObject != null) {
selectedObject = anObject;
fireContentsChanged(this, -1, -1);
}
}
#Override
public Object getSelectedItem() {
return selectedObject;
}
}
I cannot figure out what went wrong with the above code.
How to fix the code ?
(Limitation : Should not use or subclass DefaultComboBoxModel or use any third-party library.)
Related
I build a custom property and add it to a observable list. But no listener is called if property content is changed. The following code snippets shows you the 'building':
public static final class TestObject {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper();
private final BooleanProperty selected = new SimpleBooleanProperty(false);
public TestObject(String title) {
this.title.set(title);
}
public String getTitle() {
return title.get();
}
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public boolean getSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
public void setSelected(boolean selected) {
this.selected.set(selected);
}
#Override
public int hashCode() {
return Objects.hash(title.get());
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final TestObject other = (TestObject) obj;
return Objects.equals(this.title.get(), other.title.get());
}
#Override
public String toString() {
return "TestObject{" +
"title=" + title.get() +
", selected=" + selected.get() +
'}';
}
}
This is my POJO class with my internal property values like name and selected.
public static final class TestProperty extends SimpleObjectProperty<TestObject> {
public TestProperty(String name) {
super(new TestObject(name));
init();
}
public TestProperty(TestObject testObject) {
super(testObject);
init();
}
public String getTitle() {
return getValue().getTitle();
}
public void setSelected(boolean selected) {
getValue().setSelected(selected);
}
public boolean getSelected() {
return getValue().getSelected();
}
public BooleanProperty selectedProperty() {
return getValue().selectedProperty();
}
public ReadOnlyStringProperty titleProperty() {
return getValue().titleProperty();
}
#Override
public void set(TestObject testObject) {
super.set(testObject);
init();
}
#Override
public void setValue(TestObject testObject) {
super.setValue(testObject);
init();
}
private void init() {
if (get() == null)
return;
get().titleProperty().addListener((v, o, n) -> fireValueChangedEvent());
get().selectedProperty().addListener((v, o, n) -> {
fireValueChangedEvent();
});
}
}
This is my custom property based on the POJO. All property changes will fire a change event for my custom property.
#Test
public void testSimple() {
final AtomicInteger counter = new AtomicInteger(0);
final TestProperty testProperty = new TestProperty("Test");
testProperty.addListener(observable -> {
System.out.println("New state: " + testProperty.get().toString());
counter.incrementAndGet();
});
testProperty.setSelected(true);
testProperty.setSelected(false);
Assert.assertEquals(2, counter.intValue());
}
In this test you can see that the property change event works fine.
#Test
public void testList() {
final AtomicInteger counter = new AtomicInteger(0);
final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());
observableList.add(new TestProperty("Test 1"));
observableList.add(new TestProperty("Test 2"));
observableList.add(new TestProperty("Test 3"));
observableList.addListener(new ListChangeListener<TestProperty>() {
#Override
public void onChanged(Change<? extends TestProperty> change) {
System.out.println("**************");
}
});
observableList.addListener((Observable observable) -> {
System.out.println("New state: " + ((TestProperty) observable).get().toString());
counter.incrementAndGet();
});
observableList.get(1).setSelected(true);
observableList.get(2).setSelected(true);
observableList.get(1).setSelected(false);
observableList.get(2).setSelected(false);
Assert.assertEquals(4, counter.intValue());
}
But in this code you see that the observable list not called the invalidation listener nor the change listener if a property value has changed in list.
What is wrong?
Thanks.
To create an observable list that will send "list updated" notifications if properties of elements of the list change, you need to create the list with an extractor. The extractor is a Callback that maps each element of the list to an array of Observables. If any of the Observables changes, InvalidationListeners and ListChangeListeners registered with the list will be notified.
So in your testList() method, you can do
final ObservableList<TestProperty> observableList = FXCollections.observableList(
new ArrayList<>(),
(TestProperty tp) -> new Observable[]{tp.selectedProperty()});
If the title were able to change, and you also wanted the list to receive notifications when that happened, you could do that too:
final ObservableList<TestProperty> observableList = FXCollections.observableList(
new ArrayList<>(),
(TestProperty tp) -> new Observable[]{tp.selectedProperty(), tp.titleProperty()});
Note that because the extractor is a Callback (essentially a function), the implementation can be arbitrarily complex (observe one property conditionally based on the value of another, etc).
The following code shows a simple implementation for a observable list with observable values:
public class ObservableValueListWrapper<E extends ObservableValue<E>> extends ObservableListWrapper<E> {
public ObservableValueListWrapper(List<E> list) {
super(list, o -> new Observable[] {o});}}
Or you must create your list with a POJO:
final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> new Observable[] { new MyPOJOProperty(o) });
Or you use it so:
final ObservableList<MyPOJO> list = new ObservableListWrapper<>(new ArrayList(), o -> { return new Observable[] {
o.value1Property(),
o.value2Property(),
...};});
That is it! Thanks.
The ObservableList isn't notifying the listeners whenever a property contained within the list is modified, it notifies when the list is notified.
This can be seen when you modify your test:
#Test
public void testList() {
final AtomicInteger counter = new AtomicInteger(0);
final ObservableList<TestProperty> observableList = new ObservableListWrapper<>(new ArrayList<>());
observableList.addListener(new ListChangeListener<TestProperty>() {
#Override
public void onChanged(Change<? extends TestProperty> change) {
System.out.println("**************");
counter.incrementAndGet();
}
});
observableList.add(new TestProperty("Test 1"));
observableList.add(new TestProperty("Test 2"));
observableList.add(new TestProperty("Test 3"));
observableList.get(1).setSelected(true);
observableList.get(2).setSelected(true);
observableList.get(1).setSelected(false);
observableList.get(2).setSelected(false);
Assert.assertEquals(3, counter.intValue());
}
EDIT: Added an example ObserverListener decorator which provides the auto registration/deregistration of the ObservableValue change listener as desired by the OP.
/**
* Decorates an {#link ObservableList} and auto-registers the provided
* listener to all new observers, and auto-unregisters listeners when the
* item is removed from the list.
*
* #param <T>
*/
public class ObservableValueList<T extends ObservableValue> implements ObservableList<T> {
private final ObservableList<T> list;
private final ChangeListener<T> valueListener;
public ObservableValueList(ObservableList<T> list, ChangeListener<T> valueListener) {
this.list = list;
//list to existing contents of list
this.list.stream().forEach((item) -> item.addListener(valueListener));
//register listener which will add/remove listner on change to list
this.list.addListener((Change<? extends T> change) -> {
change.getAddedSubList().stream().forEach(
(item) -> item.addListener(valueListener));
change.getRemoved().stream().forEach(
(item) -> item.removeListener(valueListener));
});
this.valueListener = valueListener;
}
/* What follows is all the required delegate methods */
#Override
public int size() {
return list.size();
}
#Override
public boolean isEmpty() {
return list.isEmpty();
}
#Override
public boolean contains(Object o) {
return list.contains(o);
}
#Override
public Iterator<T> iterator() {
return list.iterator();
}
#Override
public Object[] toArray() {
return list.toArray();
}
#Override
public <T> T[] toArray(T[] ts) {
return list.toArray(ts);
}
#Override
public boolean add(T e) {
return list.add(e);
}
#Override
public boolean remove(Object o) {
return list.remove(o);
}
#Override
public boolean containsAll(Collection<?> clctn) {
return list.containsAll(clctn);
}
#Override
public boolean addAll(Collection<? extends T> clctn) {
return list.addAll(clctn);
}
#Override
public boolean addAll(int i, Collection<? extends T> clctn) {
return list.addAll(i, clctn);
}
#Override
public boolean removeAll(Collection<?> clctn) {
return list.removeAll(clctn);
}
#Override
public boolean retainAll(Collection<?> clctn) {
return list.retainAll(clctn);
}
#Override
public void replaceAll(UnaryOperator<T> uo) {
list.replaceAll(uo);
}
#Override
public void sort(Comparator<? super T> cmprtr) {
list.sort(cmprtr);
}
#Override
public void clear() {
list.clear();
}
#Override
public T get(int i) {
return list.get(i);
}
#Override
public T set(int i, T e) {
return list.set(i, e);
}
#Override
public void add(int i, T e) {
list.add(i, e);
}
#Override
public T remove(int i) {
return list.remove(i);
}
#Override
public int indexOf(Object o) {
return list.indexOf(o);
}
#Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
#Override
public ListIterator<T> listIterator() {
return list.listIterator();
}
#Override
public ListIterator<T> listIterator(int i) {
return list.listIterator(i);
}
#Override
public List<T> subList(int i, int i1) {
return list.subList(i, i1);
}
#Override
public Spliterator<T> spliterator() {
return list.spliterator();
}
#Override
public void addListener(ListChangeListener<? super T> ll) {
list.addListener(ll);
}
#Override
public void removeListener(ListChangeListener<? super T> ll) {
list.removeListener(ll);
}
#Override
public boolean addAll(T... es) {
return list.addAll(es);
}
#Override
public boolean setAll(T... es) {
return list.setAll(es);
}
#Override
public boolean setAll(Collection<? extends T> clctn) {
return list.setAll(clctn);
}
#Override
public boolean removeAll(T... es) {
return list.removeAll(es);
}
#Override
public boolean retainAll(T... es) {
return list.retainAll(es);
}
#Override
public void remove(int i, int i1) {
list.remove(i, i1);
}
#Override
public FilteredList<T> filtered(Predicate<T> prdct) {
return list.filtered(prdct);
}
#Override
public SortedList<T> sorted(Comparator<T> cmprtr) {
return list.sorted(cmprtr);
}
#Override
public SortedList<T> sorted() {
return list.sorted();
}
#Override
public void addListener(InvalidationListener il) {
list.addListener(il);
}
#Override
public void removeListener(InvalidationListener il) {
list.removeListener(il);
}
}
When adding the key it displays key added but then when I type inventory it says backpack empty, also when I go to use the item it wont let me, as its not usable.
public class Get extends AbstractCommand {
public Get (String name, String description){
super (name, description);
}
#Override
public void execute (Game game, String string) {
Item temp = game.getCurrentRoom().getItem(string);
UserInterface ui = game.getUI();
if(temp == null) ui.println("Item added\n");
else if (!(temp instanceof Moveable)) ui.println("item can not be moved");
else if (!game.getBackpack().add(temp)) ui.println("item can not be moved");
else game.getCurrentRoom().removeItem(temp);
}
}
#Override
public void execute(Game game, String string){
Item itemInBag = game.getBackpack().getItem(string);
Item itemInRoom = game.getCurrentRoom().getItem(string);
if(itemInBag!= null) {
if(itemInBag instanceof Useable){
game.setGameState(((Useable)itemInBag).use(game));
}else game.getUI().println("you can not use item");
}else if(itemInRoom!= null){
if(itemInRoom instanceof Useable){
game.setGameState(((Useable)itemInRoom).use(game));
}else game.getUI().println("this item can not be used");
}else {
game.getUI().println("take the item and use when you need to");
}
}
}
public class Inventory extends AbstractCommand {
public Inventory (String name, String description){
super (name, description);
}
#Override
public void execute (Game game, String string) {
if(((BackpackImpl)game.getBackpack()).getCount()==0) {
game.getUI().println("Backpack is empty");
}else {
for(Item i: game.getBackpack().getItems()) {
game.getUI().println(i.getName());
}
}
}
}
List<Item> items;
int maxCapacity;
public BackpackImpl (int maxCapacity){
this.maxCapacity = maxCapacity;
items = new ArrayList<Item>(5);
}
public BackpackImpl () {
this.maxCapacity = 5;
}
#Override
public boolean add(Item item){
if(items.size()>maxCapacity)
{System.out.println("your backpack canot fit no more\n");
return false;
}
items.add(item);
return true;
}
#Override
public Item remove(String string){
for(Item i: items){
if(((i.getName()).toLowerCase()).equals(string.toLowerCase())) {
items.remove(i);
return i;
}
}
return null;
}
#Override
public Item getItem(String string){
for(Item i: items){
if(((i.getName()).toLowerCase()).equals(string.toLowerCase())) {
return i;
}
}
return null;
}
#Override
public int getCapacity(){
return maxCapacity;
}
#Override
public List<Item> getItems(){
return items;
}
public int getCount (){
return items.size();
}
public void clear(){
items.clear();
}
}
Due to the "if/else (if)" construction in your Get.execute method, a new item is never added via the BackpackImpl.add() method.
Revise your Get.execute method and only print "Item added" when your code has actually called the BackpackImpl.add() method. Also, to keep your code readable, always use {} when using "if/else (if)" constructions. E.g.:
if (temp == null) {
ui.println("Item added\n");
} else if (!(temp instanceof Moveable || game.getBackpack().add(temp))) {
ui.println("item can not be moved");
} else {
game.getCurrentRoom().removeItem(temp);
}
I've created a ComboBoxModel class which extends AbstractListModel. I can add item to the combobox, but when I try to remove, I get an exception
Exception in thread "AWT-EventQueue-0"
java.lang.IllegalArgumentException: null source
at line
this.fireIntervalRemoved(selectedItem, itemIndex, itemIndex);
public class TComboBoxModel extends AbstractListModel implements ComboBoxModel {
private int itemIndex;
private Object selectedItem = null;
private ArrayList<Object> itemList;
public TComboBoxModel() {
itemList = new ArrayList<>();
}
public void addItem(String item) {
this.itemList.add(item);
this.fireIntervalAdded(item, itemIndex, itemIndex);
}
public void removeItem() {
if (itemIndex >= 0 && itemIndex < getSize()) {
this.itemList.remove(itemIndex);
this.fireIntervalRemoved(selectedItem, itemIndex, itemIndex);
}
}
#Override
public void setSelectedItem(Object anObject) {
if ((selectedItem != null && !selectedItem.equals(anObject)) || selectedItem == null && anObject != null) {
this.selectedItem = anObject;
this.fireContentsChanged(anObject, -1, -1);
}
}
#Override
public Object getSelectedItem() {
return selectedItem;
}
#Override
public int getSize() {
return itemList.size();
}
#Override
public Object getElementAt(int index) {
return itemList.get(index).toString();
}
public int getItemIndex() {
return itemIndex;
}
public void increaseItemIndex() {
itemIndex++;
}
public void decreaseItemIndex() {
itemIndex--;
}
}
Pass this to the fire* methods in the model. The event source is the model, not the item.
From the documentation:
source - the ListModel that changed, typically "this"
You should probably change it to say:
if (selectedItem != null) {
fireIntervalRemoved(this, itemIndex, itemIndex);
}
Since you can't remove an item unless you know which one to remove by having a selected item.
You are going to have to be setting the itemIndex variable appropriately too.
public void setSelectedItem(Object anObject) {
if ((selectedItem != null && !selectedItem.equals(anObject)) || selectedItem == null && anObject != null) {
this.selectedItem = anObject;
this.fireContentsChanged(anObject, -1, -1);
itemIndex = ... index in itemList where anObject is located (or -1 if not found) ...
}
}
Thanks to #kiheru for pointing out the problem with the 1st argument.
I have a simple ListModel, that is filterable and is used in a JList...
It uses the following code...
public class FilteredListModel extends AbstractListModel
{
private List<LineData> data = null;
private final ArrayList<Integer> indices = new ArrayList<Integer>();
public FilteredListModel()
{
}
public void setData(List<LineData> data)
{
this.data = data;
doFilter();
}
public void doFilter()
{
int oldSize = indices.size();
indices.clear();
if (data != null)
{
int count = data.size();
for (int i = 0; i < count; i++)
{
IFiltererListObject element = (IFiltererListObject) data.get(i);
if (element.isVisible())
indices.add(i);
}
}
fireContentsChanged(this, 0, getSize() - 1);
if (oldSize > getSize())
fireIntervalRemoved(this, getSize(), oldSize - 1);
}
#Override
public int getSize()
{
return indices.size();
}
#Override
public Object getElementAt(int index)
{
return data.get(indices.get(index));
}
#Override
public void addListDataListener(ListDataListener l)
{
// TODO Auto-generated method stub
//doFilter();
}
#Override
public void removeListDataListener(ListDataListener l)
{
// TODO Auto-generated method stub
//doFilter();
}
}
The strange thing about it is, that it is not working, just if I click for example outside the window, the JList with the ListModel get's correctly updated...
What am I missing here?
The problem is that the addListDataListener and removeListDataListener methods are empty. This means the JList can no longer attach its listener to the model. The call fireContentsChanged will do nothing, as the super class isn't aware of any listeners.
Either do not override those methods, or make sure you call super.addListDataListener as well.
#Robin please DYM???
import java.util.ArrayList;
import javax.swing.AbstractListModel;
import javax.swing.MutableComboBoxModel;
//usage == new JComboBox(new SectionComboBoxModel(new ArrayList());
public class SectionComboBoxModel extends AbstractListModel implements MutableComboBoxModel {
private static final long serialVersionUID = 1L;
private Object selectedItem;
private ArrayList<Object> sections;
public SectionComboBoxModel(ArrayList<Object> arrayList) {
sections = arrayList;
}
#Override
public Object getSelectedItem() {
return selectedItem;
}
#Override
public void setSelectedItem(Object newValue) {
selectedItem = newValue;
}
#Override
public int getSize() {
return sections.size();
}
#Override
public Object getElementAt(int i) {
return sections.get(i);
}
public void setElementAt(Object newValue, int i) {
this.fireContentsChanged(newValue, i, i);
this.sections.set(i, newValue);
}
#Override
public void addElement(Object obj) {
sections.add(obj);
this.fireIntervalAdded(obj, this.getSize() - 1, this.getSize() - 1);
}
#Override
public void removeElement(Object obj) {
this.fireIntervalRemoved(obj, sections.indexOf(obj), sections.indexOf(obj));
sections.remove(obj);
}
#Override
public void insertElementAt(Object obj, int index) {
sections.add(index, obj);
this.fireIntervalAdded(obj, index, index);
}
#Override
public void removeElementAt(int index) {
this.fireIntervalRemoved(sections.get(index), index, index);
sections.remove(index);
}
public void print() {
System.out.println("\nPrinting List");
for (int i = 0; i < this.sections.size(); i++) {
System.out.println(this.sections.get(i));
}
}
public boolean contains(Object o) {
return sections.contains(o);
}
public Object[] toArray() {
return this.sections.toArray();
}
}
I want to find the method that adds nodes to a JTree dynamically, looking through the documentation and the examples, this can only be done at the constructor of the JTree.
If possible please show me the code snippets to do this.
Thanks in advance.
You need to have a custom implementation of a TreeModel and TreeNode, see bellow. Just extend LazyTreeModel and implement loadChildren().
There a few dependencies that you must replace with your implementations : LOG - your logger
and WorkerManager.getInstance().schedule(new LoadNodesWorker()) you can replace it with a Thread() - Worker is the equivalent of Runnable.
public abstract class LazyTreeModel extends DefaultTreeModel implements TreeWillExpandListener {
public LazyTreeModel(TreeNode root, JTree tree) {
super(root);
setAsksAllowsChildren(true);
tree.addTreeWillExpandListener(this);
tree.setModel(this);
}
public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
LazyTreeNode node = (LazyTreeNode) event.getPath().getLastPathComponent();
if (node.isLoaded()) {
return;
}
setLoading(node, false);
WorkerManager.getInstance().schedule(new LoadNodesWorker(node));
}
public void reloadNode(String id) {
LazyTreeNode node = findNode(id);
if (node != null) {
node.setLoaded(false);
setLoading(node, true);
WorkerManager.getInstance().schedule(new LoadNodesWorker(node));
}
}
public void reloadParentNode(String id) {
LazyTreeNode node = findParent(id);
if (node != null) {
node.setLoaded(false);
setLoading(node, true);
WorkerManager.getInstance().schedule(new LoadNodesWorker(node));
}
}
public LazyTreeNode findParent(String id) {
LazyTreeNode node = findNode(id);
if (node != null && node.getParent() != null) {
return (LazyTreeNode) node.getParent();
}
return null;
}
public void loadFirstLevel() {
setLoading((LazyTreeNode) getRoot(), false);
WorkerManager.getInstance().schedule(new LoadNodesWorker((LazyTreeNode) getRoot()));
}
public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
}
protected void setChildren(LazyTreeNode parentNode, LazyTreeNode... nodes) {
if (nodes == null) {
return;
}
int childCount = parentNode.getChildCount();
if (childCount > 0) {
for (int i = 0; i < childCount; i++) {
removeNodeFromParent((MutableTreeNode) parentNode.getChildAt(0));
}
}
for (int i = 0; i < nodes.length; i++) {
insertNodeInto(nodes[i], parentNode, i);
}
}
private void setLoading2(final LazyTreeNode parentNode, final boolean reload) {
if (reload) {
setChildren(parentNode, createReloadingNode());
} else {
setChildren(parentNode, createLoadingNode());
}
}
private void setLoading(final LazyTreeNode parentNode, final boolean reload) {
if (SwingUtilities.isEventDispatchThread()) {
setLoading2(parentNode, reload);
} else {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setLoading2(parentNode, reload);
}
});
} catch (Exception e) {
LOG.error("Cannot create loading node", e);
}
}
}
private LazyTreeNode findNode(String id) {
return findNode(id, (LazyTreeNode) getRoot());
}
private LazyTreeNode findNode(String id, LazyTreeNode parent) {
int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
LazyTreeNode node = (LazyTreeNode) parent.getChildAt(i);
if (id.equals(node.getId())) {
return node;
}
if (node.isLoaded()) {
node = findNode(id, node);
if (node != null) {
return node;
}
}
}
return null;
}
public abstract LazyTreeNode[] loadChildren(LazyTreeNode parentNode);
protected LazyTreeNode createLoadingNode() {
return new LazyTreeNode(null, "Loading...", false);
}
protected LazyTreeNode createReloadingNode() {
return new LazyTreeNode(null, "Refreshing...", false);
}
class LoadNodesWorker implements Worker {
private LazyTreeNode parentNode;
LoadNodesWorker(LazyTreeNode parent) {
this.parentNode = parent;
}
public String getName() {
return "Lazy loading of node " + parentNode.getId();
}
public void execute() throws Exception {
final LazyTreeNode[] treeNodes = loadChildren(parentNode);
if (treeNodes == null) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
parentNode.setLoaded(true);
setChildren(parentNode, treeNodes);
}
});
}
}
}
public class LazyTreeNode extends DefaultMutableTreeNode {
private boolean loaded;
private String id;
public LazyTreeNode(String id) {
this(id, null);
}
public LazyTreeNode(String id, Object userObject) {
this(id, userObject, true);
}
public LazyTreeNode(String id, Object userObject, boolean allowsChildren) {
super(userObject, allowsChildren);
this.id = id;
}
public String getId() {
return id;
}
protected boolean isLoaded() {
return loaded;
}
protected void setLoaded(boolean loaded) {
this.loaded = loaded;
}
#Override
public boolean isLeaf() {
return !getAllowsChildren();
}
}
Try this
Edit with more explanation: you want your tree model to be based on MutableTreeNode. The link above is an example from the Sun tutorial.
The Sun example tutorial mentioned by I82Much, includes a demo project, DynamicTreeDemo, that is made up of the two source files DynamicTreeDemo.java and DynamicTree.java. You should be able to get to them from these links.