I am using my own custom model for JXTree which extends from AbstractTreeTableModel
. So the option of reload / removeNodeFromParent
is not there.
I have tried using TreeModelListener
and treeModelListener.treeNodesRemoved(event)
call with every input option possible. Never is my tree's GUI getting updated. Unless i call tree.updateUI()
the changed structure is not getting reflected.(But that call is updating the entire tree and i just want the deleted node to be refreshed). I am using my custom tree editor and tree renderer. I have not written any custom tree listener.
So the question i ask is : Does listener.treeNodesRemoved()
implicitly call some code that would have the same result as tree.updateUI()
. Or do i need to write some code myself to refresh that particular parent node from which the child was deleted. Is the listener call not working because i am using custom tree editor and renderer.
EDIT :
I am posting an SSCCE. In this case i am not using any tree editor or rendrer but the issue can be seen using this code also.
public class TestListener extends JFrame{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TestListener();
}
});
}
public TestListener(){
Departement dept1 = new Departement("1ST DEPARTMENT");
Departement dept2 = new Departement("2ND DEPARTMENT");
Employee emp1 = new Employee("1ST Employee");
Employee emp2 = new Employee("2ND Employee");
Employee emp3 = new Employee("3rd Employee");
final Employee emp4 = new Employee("4th Employee");
ArrayList<Employee> empList1 = new ArrayList<Employee>();
empList1.add(emp1);
empList1.add(emp2);
final ArrayList<Employee> empList2 = new ArrayList<Employee>();
empList2.add(emp3);
empList2.add(emp4);
dept1.setEmpList(empList1);
dept2.setEmpList(empList2);
ArrayList<Departement> deptList = new ArrayList<Departement>();
deptList.add(dept1);
deptList.add(dept2);
TestModel model = new TestModel(deptList);
final JXTree rootTree = new JXTree(model);
rootTree.setShowsRootHandles(true); // to show collapse and expand icons
rootTree.setEditable(true);
rootTree.setRootVisible(false); //not to show the top root
rootTree.setVisible(true);
JButton button = new JButton("Delete Node");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
JXTree rootNew = rootTree;
empList2.remove(emp4);
TestModel model = (TestModel) rootNew.getModel();
TreeModelEvent event = new TreeModelEvent(this,
new Object[] {rootNew.getPathForRow(3)}, // harcoding because i know i am deleting from dept2
new int[]{1}, //hardcoding as i am removing emp4
new Object[] {emp4});
TreeModelListener[] listeners = model.getTreeModelListeners();
for (TreeModelListener listener : listeners) {
listener.treeNodesRemoved(event);
}
}
});
this.setLayout(new GridLayout(0, 1));
this.getContentPane().add(new JScrollPane(rootTree));
this.getContentPane().add(button);
this.setSize(new java.awt.Dimension(400, 400));
this.setLocation(280, 50);
this.setVisible(true);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
}
TestModel Class
public class TestModel extends AbstractTreeTableModel {
private final static String[] COLUMN_NAMES = { "LABEL" };
public TestModel(ArrayList<Departement> depList) {
super(depList);
this.depList = depList;
}
private ArrayList<Departement> depList;
/* (non-Javadoc)
* @see org.jdesktop.swingx.treetable.TreeTableModel#getColumnCount()
*/
@Override
public int getColumnCount() {
return COLUMN_NAMES.length;
}
/* (non-Javadoc)
* @see org.jdesktop.swingx.treetable.TreeTableModel#getValueAt(java.lang.Object, int)
*/
@Override
public Object getValueAt(Object arg0, int arg1) {
if (arg0 instanceof Employee) {
Employee emp = (Employee) arg0;
JLabel newLabel = new JLabel();
newLabel.setText(emp.getName());
return (JLabel)newLabel;
} else if (arg0 instanceof Departement) {
Departement dept = (Departement) arg0;
JLabel newLabel = new JLabel();
newLabel.setText(dept.getName());
return (JLabel)newLabel;
}
return null;
}
/* (non-Javadoc)
* @see javax.swing.tree.TreeModel#getChild(java.lang.Object, int)
*/
@Override
public Object getChild(Object arg0, int arg1) {
if (arg0 instanceof Departement) {
Departement dept = (Departement) arg0;
return dept.getEmpList().get(arg1);
}
return depList.get(arg1);
}
/* (non-Javadoc)
* @see javax.swing.tree.TreeModel#getChildCount(java.lang.Object)
*/
@Override
public int getChildCount(Object arg0) {
if (arg0 instanceof Departement) {
Departement dept = (Departement) arg0;
return dept.getEmpList().size();
}
if (arg0 instanceof Employee) {
return 0;
}
return this.depList.size();
}
/* (non-Javadoc)
* @see javax.swing.tree.TreeModel#getIndexOfChild(java.lang.Object, java.lang.Object)
*/
@Override
public int getIndexOfChild(Object arg0, Object arg1) {
Departement dept = (Departement) arg0;
Employee emp = (Employee) arg1;
return dept.getEmpList().indexOf(emp);
}
}
The Department and Employee class is fairly simple with a constructor and some getter/setters .
So when i click on the delete node button no action is happening on the tree. The UI is not getting updated at all. I am using swingx 1.6.4 version.
Department
public class Departement {
private String name;
public String getName() {
return name;
}
private ArrayList<Employee> empList;
public ArrayList<Employee> getEmpList() {
return empList;
}
public void setEmpList(ArrayList<Employee> empList) {
this.empList = empList;
}
public Departement(String name){
this.name = name;
}
}
Employee
public class Employee {
private String name;
public String getName() {
return name;
}
public Employee(String name){
this.name =name;
}
}
Technically, the reason boils down to an incorrect event (that you manually created in your action). Apart from the (minor) incorrect source, it's the path argument that's wrong: There are two constructors for a TreeEvent which you mixed up
The real issue is the manual firing under the feet of the model: it's model's inherent responsibility to notify its listeners, so best provide it with api to remove an employee. Even then don't create the event manually which can be done incorrectly easily, that's why SwingX has TreeModelSupport to ease the pain.
Unrelated to the notification issue, don't ever return view from model methods, the correct getValueAt would be something like