删除/替换唯一的子进程后,JTree.expandPath出现了奇怪的问题

时间:2013-02-28 10:18:47

标签: java swing jtree

我想起了这个SSCCE来重现我在一个更大的程序中遇到的一些奇怪的行为:

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

public class TreeExpandTest {

    private JFrame frame;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    TreeExpandTest window = new TreeExpandTest();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public TreeExpandTest() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        final JTree tree = new JTree(root);
        tree.setShowsRootHandles(true);
        final DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
        final DefaultMutableTreeNode level1 = new DefaultMutableTreeNode("Level 1");
        root.add(level1);
        DefaultMutableTreeNode level2a = new DefaultMutableTreeNode("Level 2a");
        level1.add(level2a);

        final TreeNode[] nodes = model.getPathToRoot(level1);
        tree.expandPath(new TreePath(nodes));

        frame.getContentPane().add(tree, BorderLayout.CENTER);

        JButton btnDoStuff = new JButton("Remove 2a, replace with 2b");
        frame.getContentPane().add(btnDoStuff, BorderLayout.SOUTH);
        btnDoStuff.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                level1.remove(0);
                int[] removed = {0};
                model.nodesWereRemoved(level1, removed, null);

                DefaultMutableTreeNode level2b = new DefaultMutableTreeNode("Level 2b");
                level1.insert(level2b, 0);
                int[] inserted = {0};
                model.nodesWereInserted(level1, inserted);

                //tree.collapsePath(new TreePath(nodes));
                tree.expandPath(new TreePath(nodes));
            }
        });
    }
}

要完全了解问题,请按以下步骤操作:

  1. 启动该计划。
  2. 点击底部的按钮。这应该(i)删除“Level 2a”,然后(ii)将其替换为“Level 2b”,最后(iii)重新展开“Level 1”节点,以便新插入的替换可见。
  3. 点击后,请注意“级别1”已折叠,应展开时。
  4. 这里真的很奇怪:点击“Level 1”前面的手柄展开它。请注意,没有任何反应再次单击它,它将最终扩展。这种奇怪的行为让我相信它实际上已经扩展到了开头,但不知何故画得不正确。我不知道有什么办法要求树重新绘制,我相信我正确地调用nodesWereInserted方法,这就是我能做的所有,对吧?
  5. 我找到了一个“解决”问题的解决方法,但不满足我的好奇心。

    1. 取消注释源代码中的倒数第二行,然后启动程序并再次按下该按钮。请注意,它现在完美无缺。
    2. 问题仍然存在......出了什么问题,为什么需要我的解决方法?为什么在告诉它之前我需要折叠树我希望它被扩展?

      编辑添加:只有在我删除/替换唯一的孩子时才会出现这种情况。如果有多个孩子,我删除/替换父母永远不会没有孩子,那么每件事都会按照预期行事。

1 个答案:

答案 0 :(得分:4)

通知不正确,必须是:

level1.remove(0);
int[] removed = {0};
Object[] children = new Object[]{level2a};
model.nodesWereRemoved(level1, removed, children);

注意子数组而不是null

顺便说一下,我建议尽可能使用模型api修改节点/结构(而不​​是改变其脚下的节点)。对于单节点更改,上面将是:

model.removeNodeFromParent(level2a);
DefaultMutableTreeNode level2b = new DefaultMutableTreeNode("Level 2b");
model.insertNodeInto(level2b, level1, 0);