繁体   English   中英

JTree:删除节点后更新树

[英]JTree : Update tree after deleting nodes

我正在使用自定义的JXTree自定义模型,该模型从AbstractTreeTableModel扩展。 因此,不存在reload / removeNodeFromParent选项。

我尝试将TreeModelListenertreeModelListener.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM