我正在使用我自己的JXTree自定义模型,该模型从AbstractTreeTableModel
延伸。所以reload / removeNodeFromParent
的选项不存在。
我尝试使用TreeModelListener
和treeModelListener.treeNodesRemoved(event)
调用每个输入选项。我的树的GUI永远不会更新。除非我调用tree.updateUI()
,否则更改的结构不会被反映。(但是该调用正在更新整个树,我只想刷新已删除的节点)。我正在使用自定义树编辑器和树渲染器。我没有写任何自定义树监听器。
所以我问的问题是: listener.treeNodesRemoved()
隐式调用一些与tree.updateUI()
具有相同结果的代码。或者我是否需要自己编写一些代码来刷新删除子项的特定父节点。侦听器调用是否无效,因为我使用的是自定义树编辑器和渲染器。
编辑:
我发布的是SSCCE。在这种情况下,我没有使用任何树编辑器或报告器,但也可以使用此代码看到问题。
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);
}
}
使用构造函数和一些getter / setter,Department和Employee类相当简单。
因此,当我点击删除节点按钮时,树上没有任何动作。用户界面根本没有得到更新。我使用的是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;
}
}
答案 0 :(得分:2)
您可以使用reload()
版本作为指南,在自定义模型中添加DefaultTreeTableModel
方法。有一个示例here调用fireTreeStructureChanged()
。
答案 1 :(得分:2)
从技术上讲,原因归结为不正确的事件(您在操作中手动创建)。除了(次要的)不正确的源之外,它的路径参数是错误的:有一个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);
与通知问题无关,不要从模型方法返回 view ,正确的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;
}