2013-02-25 77 views
4

我已經使用Lazy Loading實現了一棵樹。第一級節點是在樹創建時創建的,其中只有當用戶擴展任何特定節點時才創建子節點。展開收起展開JTree的問題延遲加載

數據來自數據庫,我們向數據庫發出查詢以填充子節點。實現了TreeExpansionListener並使用了treeExpanded方法的重載實現。在展開時,我刪除選定節點的所有子節點,進行數據庫查詢並將記錄添加爲選定節點的子節點。在將任何節點添加到樹之前,會將虛擬子節點添加到該節點。使用DefaultMutableTreeNode。

到目前爲止這樣好,它按期望工作正常。

問題1 - 因爲你是一個DB擴展的調用,所以如果一個節點被摺疊並再次展開,我將執行一次數據庫訪問並再次處理一個數據......這個想法是不加載節點新鮮,如果已經擴大...

問題2 - 如果我不得不做一個強制刷新即重新加載樹並保持擴展狀態。現在處於工作狀態......如何在修復上述問題1的同時獲得同樣的結果?

欣賞這方面的任何幫助。

+0

如果一個節點是摺疊,請不要清除數據。當它再次被擴展時,檢查節點是否已經有數據... – vikingsteve 2013-02-25 20:05:42

+0

我正在重寫treeCollapsed方法,並且什麼都不做。我怎樣才能阻止數據消失。 – newbie 2013-02-25 20:08:41

+0

在treeExpanded上,檢查父節點是否包含子節點。如果是的話。不能重新加載任何東西 – MadProgrammer 2013-02-25 20:28:08

回答

8

正如MadProgrammer解釋的,這裏是表示一個JTree加載動態數據的小的演示例子作爲樹中的節點膨脹(並顯示一個精美加載條作爲獎金):

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.beans.Transient; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JFrame; 
import javax.swing.JProgressBar; 
import javax.swing.JScrollPane; 
import javax.swing.JTree; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.TreeExpansionEvent; 
import javax.swing.event.TreeWillExpandListener; 
import javax.swing.tree.DefaultMutableTreeNode; 
import javax.swing.tree.DefaultTreeModel; 
import javax.swing.tree.ExpandVetoException; 
import javax.swing.tree.MutableTreeNode; 
import javax.swing.tree.TreePath; 

public class TestJTree { 

    public static class MyTreeNode extends DefaultMutableTreeNode { 

     private boolean loaded = false; 

     private int depth; 

     private final int index; 

     public MyTreeNode(int index, int depth) { 
      this.index = index; 
      this.depth = depth; 
      add(new DefaultMutableTreeNode("Loading...", false)); 
      setAllowsChildren(true); 
      setUserObject("Child " + index + " at level " + depth); 
     } 

     private void setChildren(List<MyTreeNode> children) { 
      removeAllChildren(); 
      setAllowsChildren(children.size() > 0); 
      for (MutableTreeNode node : children) { 
       add(node); 
      } 
      loaded = true; 
     } 

     @Override 
     public boolean isLeaf() { 
      return false; 
     } 

     public void loadChildren(final DefaultTreeModel model, final PropertyChangeListener progressListener) { 
      if (loaded) { 
       return; 
      } 
      SwingWorker<List<MyTreeNode>, Void> worker = new SwingWorker<List<MyTreeNode>, Void>() { 
       @Override 
       protected List<MyTreeNode> doInBackground() throws Exception { 
        // Here access database if needed 
        setProgress(0); 
        List<MyTreeNode> children = new ArrayList<TestJTree.MyTreeNode>(); 
        if (depth < 5) { 
         for (int i = 0; i < 5; i++) { 
          // Simulate DB access time 
          Thread.sleep(300); 
          children.add(new MyTreeNode(i + 1, depth + 1)); 
          setProgress((i + 1) * 20); 
         } 
        } else { 
         Thread.sleep(1000); 
        } 
        setProgress(0); 
        return children; 
       } 

       @Override 
       protected void done() { 
        try { 
         setChildren(get()); 
         model.nodeStructureChanged(MyTreeNode.this); 
        } catch (Exception e) { 
         e.printStackTrace(); 
         // Notify user of error. 
        } 
        super.done(); 
       } 
      }; 
      if (progressListener != null) { 
       worker.getPropertyChangeSupport().addPropertyChangeListener("progress", progressListener); 
      } 
      worker.execute(); 
     } 

    } 

    protected void initUI() { 
     JFrame frame = new JFrame(TestJTree.class.getSimpleName()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     MyTreeNode root = new MyTreeNode(1, 0); 
     final DefaultTreeModel model = new DefaultTreeModel(root); 
     final JProgressBar bar = new JProgressBar(); 
     final PropertyChangeListener progressListener = new PropertyChangeListener() { 

      @Override 
      public void propertyChange(PropertyChangeEvent evt) { 
       bar.setValue((Integer) evt.getNewValue()); 
      } 
     }; 
     JTree tree = new JTree() { 
      @Override 
      @Transient 
      public Dimension getPreferredSize() { 
       Dimension preferredSize = super.getPreferredSize(); 
       preferredSize.width = Math.max(400, preferredSize.width); 
       preferredSize.height = Math.max(400, preferredSize.height); 
       return preferredSize; 
      } 
     }; 
     tree.setShowsRootHandles(true); 
     tree.addTreeWillExpandListener(new TreeWillExpandListener() { 

      @Override 
      public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { 
       TreePath path = event.getPath(); 
       if (path.getLastPathComponent() instanceof MyTreeNode) { 
        MyTreeNode node = (MyTreeNode) path.getLastPathComponent(); 
        node.loadChildren(model, progressListener); 
       } 
      } 

      @Override 
      public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { 

      } 
     }); 
     tree.setModel(model); 
     root.loadChildren(model, progressListener); 
     frame.add(new JScrollPane(tree)); 
     frame.add(bar, BorderLayout.SOUTH); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, 
      UnsupportedLookAndFeelException { 
     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new TestJTree().initUI(); 
      } 
     }); 
    } 
} 
+0

+1的獎金 – MadProgrammer 2013-02-25 23:09:54

+0

謝謝你的演示....我能夠解決這個問題使用MadProgrammer評論.... – newbie 2013-02-27 23:38:03

+0

您能否請建議我如何刷新此樹(使用延遲加載填充),以便重新獲取所有展開的節點並保留展開狀態。我能夠存儲當前的擴展狀態,但問題是expandRow(),它擴展了行號的樹,是動態的,它最終打開了一些其他行... expandPath是正確的選擇,但由於某種原因,不工作: ( – newbie 2013-02-27 23:50:50

1

一旦節點已經填充,簡單地不重新填充它。在treeExpanded上,只需檢查父節點是否有任何子節點,如果是,則不要重新加載任何內容。

您需要提供刷新父節點的能力。我通常使用JPopupMenu來做到這一點。

+0

謝謝你的演示....我能夠使用MadProgrammer的意見解決問題.. – newbie 2013-02-27 23:39:17