[英]JTree : Update tree after deleting nodes
我正在使用自定义的JXTree自定义模型,该模型从AbstractTreeTableModel
扩展。 因此,不存在reload / removeNodeFromParent
选项。
我尝试将TreeModelListener
和treeModelListener.treeNodesRemoved(event)
调用与每个可能的输入选项一起使用。 我的树的GUI从未更新过。 除非我调用tree.updateUI()
,否则更改后的结构不会得到反映。(但是该调用正在更新整个树,我只希望刷新已删除的节点)。 我正在使用我的自定义树编辑器和树渲染器。 我尚未编写任何自定义树侦听器。
所以我问的问题是: listener.treeNodesRemoved()
是否隐式调用某些与tree.updateUI()
具有相同结果的代码。 还是我需要自己编写一些代码来刷新删除了孩子的特定父节点 。 侦听器调用是否无法正常运行,因为我正在使用自定义树编辑器和渲染器。
编辑:
我正在发布SSCCE。 在这种情况下,我没有使用任何树编辑器或rendrer,但是使用此代码也可以看到问题。
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类
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);
}
}
Department和Employee类非常简单,带有一个构造函数和一些getter / setter方法。
因此,当我单击删除节点按钮时,树上没有任何动作。 用户界面根本没有更新。 我正在使用swingx 1.6.4版本。
部
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;
}
}
雇员
public class Employee {
private String name;
public String getName() {
return name;
}
public Employee(String name){
this.name =name;
}
}
您可以使用DefaultTreeTableModel
版本作为指南将reload()
方法添加到自定义模型中。 这里有一个例子在这里调用fireTreeStructureChanged()
。
从技术上讲,原因归结为一个不正确的事件(您在操作中手动创建的事件)。 除了(次要的)不正确的来源以外,还有路径参数是错误的:您混合使用了TreeEvent的两个构造函数
// one taking a TreePath
public TreeModelEvent(Object source, TreePath path, int[] childIndices,
Object[] children)
// the other taking an array of nodes to the root
public TreeModelEvent(Object source, Object[] path, int[] childIndices,
Object[] children)
// mixture (**WRONG**)
TreeModelEvent event = new TreeModelEvent(this,
// this is an array with the path as single element
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});
// technically correct (but **don't** - TreeModelSupport does it for you :-)
TreeModelEvent event = new TreeModelEvent(this,
// this is an array with the path as single element
rootNew.getPathForRow(3), // harcoding because i know i am deleting from dept2
new int[]{1}, //hardcoding as i am removing emp4
new Object[] {emp4});
真正的问题是在模型的脚下手动解雇:通知模型的侦听器是模型的固有责任,因此最好向其提供api以删除雇员。 即使这样不手动创建的事件可以被错误地轻松完成,这就是为什么SwingX有TreeModelSupport以缓解疼痛。
// public api in your custom model
public void removeEmployee(Departement dept, Employee emp) {
TreePath path = new TreePath(new Object[] {depList, dept});
int index = dept.empList.indexOf(emp);
dept.empList.remove(emp);
modelSupport.fireChildRemoved(path, index, emp);
}
// its usage in application code
TestModel model = (TestModel) rootTree.getModel();
model.removeEmployee(dept2, emp4);
与通知问题无关,永远不要从模型方法返回视图 ,正确的getValueAt类似于
@Override
public Object getValueAt(Object arg0, int arg1) {
if (arg0 instanceof Employee) {
Employee emp = (Employee) arg0;
return emp.getName();
} else if (arg0 instanceof Departement) {
Departement dept = (Departement) arg0;
return dept.getName();
}
return null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.