2012-02-13 4 views
2

もしない、私は今、私はGUIスレッドでデータをロードすることは時間がかかること、それを実装し、認識しているthis website in chapter "4.2 OutlineNode.java"ダイナミックJTreeのとSwingUtilities.invokeLaterを()私のダイナミックJTreeのを作成するには、何も

にダイナミックJTreesについてのチュートリアルを読んでいましたまた醜いです。したがって、子を展開して、TreeNode要素をツリーに追加するスレッドを追加しました。

private void getChildNodes() { 
    areChildrenDefined = true; 
    Thread t = new Thread(new Runnable() 
    { 
     @Override 
     public void run() { 
     System.out.println("Expand"); 
      final List<DECTTreeNode> listNodes = new ArrayList<DECTTreeNode>(); 
      if (castNode().canExpand()) 
      { 
       for(DECTNode crt : castNode().getChildren()) 
       { 
        DECTTreeNode treeNode = new DECTTreeNode(crt); 
        listNodes.add(treeNode); 
       } 

       try { 
        SwingUtilities.invokeAndWait(new Runnable() 
        { 
         @Override 
         public void run() { 
          System.out.println(listNodes.size()); 
          for (DECTTreeNode crt : listNodes) 
          { 
           add(crt); // <==== Adds the node to the JTree 
          } 
         } 

        }); 
        //}).run(); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 

      } 
     } 

    }); 
    t.start(); 
} 

スレッドなしで問題なく動作します。スレッドを追加してaddコールをSwingUtilities.invokeAndWait(...)に入れると、子は展開されているように見えますが、ツリーには表示されません。

私はすでにrevalidate()repaint()を試してみました。効果はありません。

これらの要素を表示させるにはどうすればよいですか?

ありがとうございます。

+0

は、私はあなたがTreeModelのノードをプリントアウトしてくださいすることができ、このコードは何もしなかったことを考えます、何かが含まれている場合 – mKorbel

+0

前述したように:スレッド化しないとうまくいくようです。私がそれらを展開し、同じスレッドにすべてのノードを表示すると、動作します。 – Atmocreations

答えて

2
@Override 
public void treeWillExpand(TreeExpansionEvent e) throws ExpandVetoException { 
    CustomTreeNode t = (CustomTreeNode) e.getPath().getLastPathComponent(); 
    t.addChildLoadedListener(new ChildLoadedListener() { 
     @Override 
     public void childLoaded(TreeNode parent) { 
      ((CustomTreeNode) parent).setExpanded(true); 
      expandPath(new TreePath(((CustomTreeNode) parent).getPath())); 
     } 
    }); 
    if (!t.isExpanded()) { 
     factory.loadChildren(t); 
     throw new ExpandVetoException(null); 
    } 
} 

public void treeWillCollapse(TreeExpansionEvent e) throws ExpandVetoException { 
    CustomTreeNode t = (CustomTreeNode) e.getPath().getLastPathComponent(); 
    t.setExpanded(false); 
} 

からRunnable#Threadを呼び出すためには、私をJugdeか。これは私のために働く。 CustomTreeNodeはdefaultMutableTreeNodeから拡張され、子供が工場でロードされたときに呼び出される、自己書き換え型のChildLoadedListenerが追加されています。 isExpandedブール値は、無限ループを回避することです。 ファクトリは、子をロードして実行するSwingWorkerを作成します。その後、ChilLoadedListenerが呼び出され、ツリーが再び展開されます。これは助けたり、あなたの問題;-)を考える少なくとも助けます

希望

EDIT:

@Override 
public void loadChildren(CustomTreeNode tn) { 
    ctn = tn; 
    LoadChildrenWorker worker = new LoadChildrenWorker(); 
    worker.execute(); 
} 


private class LoadChildrenWorker extends SwingWorker<String, Object> { 

      @Override 
    protected String doInBackground() throws Exception { 
        //load source here and return a string when finished. 
        //In my case its a string repesentation of a directory 
    } 

    @Override 
    protected void done() { 
      //with get(), you get the string from doBackground() 
      for (String str : parseFromOutput(get())) { 
        if (str.endsWith("/")) { 
         ctn.add(new CustomTreeNode("Directory"); 
        } else { 
         ctn.add(new CustomTreeNode("Leaf"); 
        } 
      } 
      //call listeners 
      ctn.fireChildrenLoaded(); 
    } 
+0

あなたの応答に感謝します。あなたの 'SwingWorker'の' finished() 'メソッドを教えてください。私は以前に登録されたリスナーを反復処理しながら、何とか 'ConcurrentModificationException'を取得します。多くのありがとう – Atmocreations

+0

私はSwingWorkerコードを追加しました。 – NotANormalNerd

+0

ありがとうございました。私は何かを忘れてしまった...今それは動作する! – Atmocreations

0

invokeAndWaitinvokeLaterに置き換えてください。

+0

既に試してみました。どちらもうまくいきませんでした。 – Atmocreations

3

チェックは、あなたのadd()メソッドが正しいTreeModelEvent

+0

混乱して申し訳ありません。私の質問のスニペットは 'extends DefaultMutableTreeNode'クラスの一部です。したがって、 'add()'は親の 'DefaultMutableTreeNode'が行うことを行います。 – Atmocreations

+0

それが問題です。 DefaultMutableTreeNodeは、add()が呼び出されたときにイベントを発生させません。モデルを通してノードを追加する必要があります。DefaultTreeModel#insertNodeInto(または手動で正しいイベントを起動する)を参照してください。 –

1

を発射することを私は今、私が働いているプロジェクトで同じ問題を持っていました。

私はTreeWillExpandListenerを使用して、いつツリーをロードする必要があるかを判断します。 (LazyLoading) ツリーが展開されたときに、サーバー出力からノードを解析しなければならなかったので、ロードされたノードをキャッチしました。

あなたが直面している問題は、子供がロードされる前にツリーが拡張されていることです。 ExpandVetoExceptionかそのようなものを投げて、あなたの子供が積まれるまで待ちます。ツリーを展開します。この場合、すべてが正しく表示されます。

希望はあなたの問題を願っています。あなたはスイングで作業する場合、あなたはより良いSwingWorkerのを使用

:あなたのノード

EDITを参照してください> - >今、ツリーを展開 -

Exapand-> expand-> loadchildren-> addChildrenを停止します。私にとってはうまくいく。

+0

でも、私はそれを試していない、私はそれが動作しないと思います:ノードを折りたたむとき、私はコンテンツを削除しません。したがって、ノードを折りたたんだり再展開したりするときには、このノードを表示する必要があります。しかし、そうではありません。それともこれはまだ別の問題ですか? – Atmocreations

+0

私は同じ問題を抱えていました。ツリーが開くたびに子供たちが読み込まれます。あなたが子供を積み込む前に毎回木を開きます。 'System.out.println()'は私たちの友人です;-)(私の元教師がいつも言ったように) – NotANormalNerd

+0

あなたのソリューションはあなたのために働くようですが、これは醜いハックのように見えますか?まあ...言及:私は子供が一度だけ拡張されることを保証するフラグがあります。彼らはリストに保管され、返されます... – Atmocreations

3

、ウォルター+1での提案を拡大するJButton addButton

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 
import javax.swing.event.*; 
import javax.swing.tree.*; 

public class DynamicTreeDemo extends JPanel implements ActionListener { 

    private static final long serialVersionUID = 1L; 
    private int newNodeSuffix = 1; 
    private static String ADD_COMMAND = "add"; 
    private static String REMOVE_COMMAND = "remove"; 
    private static String CLEAR_COMMAND = "clear"; 
    private DynamicTree treePanel; 

    public DynamicTreeDemo() { 
     super(new BorderLayout()); // Create the components. 
     treePanel = new DynamicTree(); 
     populateTree(treePanel); 
     JButton addButton = new JButton("Add"); 
     addButton.setActionCommand(ADD_COMMAND); 
     addButton.addActionListener(this); 
     JButton removeButton = new JButton("Remove"); 
     removeButton.setActionCommand(REMOVE_COMMAND); 
     removeButton.addActionListener(this); 
     JButton clearButton = new JButton("Clear"); 
     clearButton.setActionCommand(CLEAR_COMMAND); 
     clearButton.addActionListener(this); // Lay everything out. 
     treePanel.setPreferredSize(new Dimension(300, 150)); 
     add(treePanel, BorderLayout.CENTER); 
     JPanel panel = new JPanel(new GridLayout(0, 3)); 
     panel.add(addButton); 
     panel.add(removeButton); 
     panel.add(clearButton); 
     add(panel, BorderLayout.SOUTH); 
    } 

    public void populateTree(DynamicTree treePanel) { 
     String p1Name = "Parent 1"; 
     String p2Name = "Parent 2"; 
     String c1Name = "Child 1"; 
     String c2Name = "Child 2"; 
     DefaultMutableTreeNode p1, p2; 
     p1 = treePanel.addObject(null, p1Name); 
     p2 = treePanel.addObject(null, p2Name); 
     treePanel.addObject(p1, c1Name); 
     treePanel.addObject(p1, c2Name); 
     treePanel.addObject(p2, c1Name); 
     treePanel.addObject(p2, c2Name); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     String command = e.getActionCommand(); 
     if (ADD_COMMAND.equals(command)) { // Add button clicked 
      treePanel.addObject("New Node " + newNodeSuffix++); 
     } else if (REMOVE_COMMAND.equals(command)) { // Remove button clicked 
      treePanel.removeCurrentNode(); 
     } else if (CLEAR_COMMAND.equals(command)) { // Clear button clicked. 
      treePanel.clear(); 
     } 
    } 


    private static void createAndShowGUI() { // Create and set up the window. 
     JFrame frame = new JFrame("DynamicTreeDemo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Create and set up the content pane. 
     DynamicTreeDemo newContentPane = new DynamicTreeDemo(); 
     newContentPane.setOpaque(true); // content panes must be opaque 
     frame.setContentPane(newContentPane); // Display the window. 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 


class DynamicTree extends JPanel { 
    private static final long serialVersionUID = 1L; 

    private DefaultMutableTreeNode rootNode; 
    private DefaultTreeModel treeModel; 
    private JTree tree; 
    private Toolkit toolkit = Toolkit.getDefaultToolkit(); 

    public DynamicTree() { 
     super(new GridLayout(1, 0)); 
     rootNode = new DefaultMutableTreeNode("Root Node"); 
     treeModel = new DefaultTreeModel(rootNode); 
     treeModel.addTreeModelListener(new MyTreeModelListener()); 
     tree = new JTree(treeModel); 
     tree.setEditable(true); 
     tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 
     tree.setShowsRootHandles(true); 
     JScrollPane scrollPane = new JScrollPane(tree); 
     add(scrollPane); 
    } 

    public void clear() { 
     rootNode.removeAllChildren(); 
     treeModel.reload(); 
    } 

    public void removeCurrentNode() { 
     TreePath currentSelection = tree.getSelectionPath(); 
     if (currentSelection != null) { 
      DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) (currentSelection.getLastPathComponent()); 
      MutableTreeNode parent = (MutableTreeNode) (currentNode.getParent()); 
      if (parent != null) { 
       treeModel.removeNodeFromParent(currentNode); 
       return; 
      } 
     } // Either there was no selection, or the root was selected. 
     toolkit.beep(); 
    } 


    public DefaultMutableTreeNode addObject(Object child) { 
     DefaultMutableTreeNode parentNode = null; 
     TreePath parentPath = tree.getSelectionPath(); 
     if (parentPath == null) { 
      parentNode = rootNode; 
     } else { 
      parentNode = (DefaultMutableTreeNode) (parentPath.getLastPathComponent()); 
     } 
     return addObject(parentNode, child, true); 
    } 

    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child) { 
     return addObject(parent, child, false); 
    } 

    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child, boolean shouldBeVisible) { 
     DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child); 
     if (parent == null) { 
      parent = rootNode; 
     } 
     // It is key to invoke this on the TreeModel, and NOT DefaultMutableTreeNode 
     treeModel.insertNodeInto(childNode, parent, parent.getChildCount()); 
     // Make sure the user can see the lovely new node. 
     if (shouldBeVisible) { 
      tree.scrollPathToVisible(new TreePath(childNode.getPath())); 
     } 
     return childNode; 
    } 



    class MyTreeModelListener implements TreeModelListener { 

     @Override 
     public void treeNodesChanged(TreeModelEvent e) { 
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent());   /* 
      * If the event lists children, then the changed node is the child of the 
      * node we've already gotten. Otherwise, the changed node and the 
      * specified node are the same. 
      */ int index = e.getChildIndices()[0]; 
      node = (DefaultMutableTreeNode) (node.getChildAt(index)); 
      System.out.println("The user has finished editing the node."); 
      System.out.println("New value NodesChanged: " + node.getUserObject()); 
     } 

     @Override 
     public void treeNodesInserted(TreeModelEvent e) { 
      DefaultMutableTreeNode node= (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent());   /* 
      * If the event lists children, then the changed node is the child of the 
      * node we've already gotten. Otherwise, the changed node and the 
      * specified node are the same. 
      */ int index = e.getChildIndices()[0]; 
      node = (DefaultMutableTreeNode) (node.getChildAt(index)); 
      System.out.println("New value NodesInserted : " + node.getUserObject()); 
     } 

     @Override 
     public void treeNodesRemoved(TreeModelEvent e) { 
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent());   /* 
      * If the event lists children, then the changed node is the child of the 
      * node we've already gotten. Otherwise, the changed node and the 
      * specified node are the same. 
      */ int index = e.getChildIndices()[0]; 
      node = (DefaultMutableTreeNode) (node.getChildAt(index)); 
      System.out.println("New value NodesRemoved : " + node.getUserObject()); 
     } 

     @Override 
     public void treeStructureChanged(TreeModelEvent e) { 
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) (e.getTreePath().getLastPathComponent());   /* 
      * If the event lists children, then the changed node is the child of the 
      * node we've already gotten. Otherwise, the changed node and the 
      * specified node are the same. 
      */ int index = e.getChildIndices()[0]; 
      node = (DefaultMutableTreeNode) (node.getChildAt(index)); 
      System.out.println("New value StructureChanged : " + node.getUserObject()); 
     } 
    } 
} 
関連する問題