1

私はこの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)「レベル2a」を削除し、(ii)「レベル2b」に置き換え、最後に(iii)「レベル1」ノードを再拡張して、新しく挿入された置換が表示されるようにすることを想定しています。
  3. クリックした後、展開する必要があるときに「レベル1」が折りたたまれていることに注意してください。
  4. ここが本当に奇妙なところです。「レベル1」の前にあるハンドルをクリックして展開します。何も起こらないことに注意してください!もう一度クリックすると、ようやく展開されます。この奇妙な振る舞いは、実際には最初から拡張されたものの、どういうわけか間違って描かれていると私に信じさせます。木を塗り替えるために呼び出す方法を私は知りません、そして私はnodesWereInsertedメソッドを正しく呼び出していると信じています、それは本当に私ができるすべてですよね?

問題を「修正」する回避策を見つけましたが、好奇心を満たしていません。

  1. ソースコードの最後から2番目の行のコメントを解除してから、プログラムを起動してボタンをもう一度押します。これで完全に機能することに注意してください。

問題は残っています...何がうまくいかないのですか、そしてなぜ私の回避策が必要なのですか?拡大したいことを伝える前に、なぜツリーを折りたたむ必要があるのですか?

追加するために編集:これは、一人っ子を削除/交換する場合にのみ発生します。複数の子があり、親が子を持たないように削除/置換した場合、すべてが期待どおりに動作します。

4

1 に答える 1

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);
于 2013-02-28T10:34:46.827 に答える