2

Java Swingにノードを動的に追加しようとするJTreeと、ノードが絶えず追加されている間、ユーザーは階層を参照して折りたたむことができるはずです。Thread.sleep(10)ループにを追加すると、正常に機能します。しかし、これは汚いハックです...

これは、この問題を引き起こす簡略化されたコードです。これを実行し、ルートノードをダブルクリックして展開/折りたたむと(ノードが追加されている間)、が表示されArrayIndexOutOfBoundsExceptionます。これを追加しても、Thread.sleep(10)これは発生しません。これはスレッドの問題だと思いますが、これを同期する方法がわかりませんか?ヒントをいただければ幸いです。

public static void main(String[] args) throws InterruptedException {
    final JFrame frame = new JFrame();
    frame.setSize(600, 800);
    frame.setVisible(true);

    MutableTreeNode root = new DefaultMutableTreeNode("root");
    final DefaultTreeModel model = new DefaultTreeModel(root);
    final JTree tree = new JTree(model);
    frame.add(new JScrollPane(tree));

    while (true) {
        MutableTreeNode child = new DefaultMutableTreeNode("test");
        model.insertNodeInto(child, root, root.getChildCount());
        tree.expandRow(tree.getRowCount() - 1);

        // uncommenting this to make it work
        // Thread.sleep(10);
    }
}

これをタイピング中の検索アプリケーションに使用したいので、(ほぼ)即座に結果を出すことが私にとって不可欠です。

編集:迅速な回答をありがとう!SwingUtilities.invokeLater()問題を解決します。

私は今これをします:

  1. 内に100個のアイテムを追加しますSwingUtilities.invokeLater();
  2. 100項目後、GUIを更新できるように、これを実行します。

    // just wait so that all events in the queue can be processed
    SwingUtilities.invokeAndWait(new Runnable() {
        public void run() { }; 
    });
    

このように、私は非常に応答性の高いGUIを使用しており、完全に機能します。ありがとう!

4

3 に答える 3

4

tree.expandRow はイベント スレッドで実行する必要があるため、ループを次のように変更します。

while (true) 
{
        MutableTreeNode child = new DefaultMutableTreeNode("test");
        model.insertNodeInto(child, root, root.getChildCount());
        final int rowToExpand = tree.getRowCount() - 1; // ? does this work ?
        SwingUtilities.invokeLater(new Runnable()
        {
           public void run()
           {
               tree.expandRow(rowToExpand);
           }
        });

}

その際、おそらく、ツリー モデルが使用しているリストが同期されていることを確認する必要があります。そのため、ペイント スレッドがツリーをトラバースしている間はコレクションに挿入しないでください。

于 2009-01-21T19:39:00.830 に答える
0

Swingはスレッドに対して敵対的であるため、AWT Event Diaptch Thread(EDT)でSwingの操作を行います。

無限ループはナンセンスなので、提案を思いつくのは難しいです。私が考えることができる最も良い同等物は、コードを再度実行するために偶数を投稿することを繰り返すことです。イベントキューには特定の優先順位があるため、それでも機能するかどうかはわかりません。

public static void main(String[] args) throws InterruptedException {
    java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
        runEDT();
    }});
}
private static void runEDT() {
    assert java.awt.EventQueue.isDispatchThread();

    final JFrame frame = new JFrame();
    frame.setSize(600, 800);
    frame.setVisible(true);

    final MutableTreeNode root = new DefaultMutableTreeNode("root");
    final DefaultTreeModel model = new DefaultTreeModel(root);
    final JTree tree = new JTree(model);
    frame.add(new JScrollPane(tree));
    frame.validate();

    new Runnable() { public void run() {
        final MutableTreeNode child = new DefaultMutableTreeNode("test");
        model.insertNodeInto(child, root, root.getChildCount());
        tree.expandRow(tree.getRowCount() - 1);

        final Runnable addNode = this; // Inner class confusion...
        java.awt.EventQueue.invokeLater(addNode);
    }}.run();
}

(免責事項:コンパイルまたはテストされていません。)

于 2009-01-21T19:58:18.000 に答える
-1

tree.expandRowコマンドをTreeModelListenertreeNodesInsertedイベントから実行して、モデルが更新された後にのみ実行されるようにすることができます。

于 2009-01-21T19:27:38.810 に答える