2013-02-22 24 views
5

Sunucumdaki dosya sisteminin bir bölümünü yansıtan bir dosya hiyerarşisini görüntülemek için kullanılan bir DefaultTreeModel ile desteklenen bir JTree içeren bir uygulamam var. Bu benim istemci uygulaması olarak). Ayrıca, istemci uygulamasının görüntülemesi gereken verileri sağlayan bir sunucu uygulamasına da sahibim (bunu sunucu uygulamasına olarak bakacağım). Ben "tembel yük çocuklar" yaklaşımı kullanıyorum, bu yüzden kullanıcı ilgileniyorsa sadece ağacımdaki dosyaları yüklemek zorundayım. Tembel yük yaklaşım: Ben genişleyen düğümün o olmaya seçim yolu ayarlayın treeWillExpand(TreeExpansionEvent evt) JTree ile Genişletme/Seçim Durumunu Geri Yükleme Tempoyu Yükleme ile

  • geçersiz

    1. .
    2. Sonra, o düğümün çocuklarını soran sunucuya bir mesaj gönderiyorum.
    3. Sunucu yanıt verdiğinde, son seçilen yol bileşenini alırım.
    4. Ardından, döndürülen veri dosyaları için DefaultTreeModel.insertNodeInto() kullanıyorum.
    5. Son olarak DefaultTreeModel.nodeStructureChanged() numaralı telefonu arıyorum.

    Yukarıdaki işler iyi ve ben çocuklara tembelce yükleme ile ilgili herhangi bir sorunum yok. Yeni veri sunucuya yüklendiğinde sorunum geliyor ve ağacı yalnızca yeni verileri içermekle değil, genişletme durumunu ve seçilen düğümü ağacın güncellenmesinden önce ne yapacağıyla ayarlamak istiyorum (böylece kullanıcı sadece yeni veriler göründüğü için ağacın etrafında sarsılmaz.

    1. Yeni veri sunucusuna yüklenir
    2. Sunucu uygulaması arşivleri bu veri ve yüklenen dosyalar hakkında bilgi içeren bir veritabanı doldurur: şöyle akışıdır.
    3. Sunucu uygulaması, istemci verilerini yeni verilerin yüklendiğini bildirir.
    4. İstemci uygulaması JTree.getExpandedDescendants()
    5. İstemci uygulamasını kullanarak ağacın genişletme durumu JTree.getSelectionPath()
    6. İstemci uygulamasını kullanarak ağacın seçimi yolu DefaultTreeModel tüm düğümlerin kaldırır kaydeder kaydeder.
    7. İstemci uygulaması, kök düğümden başlayarak sunucudan veri talep eder.
    8. İstemci uygulaması, numaralandırmadaki her TreePath öğesinde JTree.expandPath() numaralı telefonu arayarak JTree.getExpandedDescendants() numaralı döndürülen ağaç yolu numaralandırması arasında geçiş yapar.
    9. İstemci uygulaması, seçilen ağaç yolunu ayarlar.

    Sorunum, ağacın GUI'sini denemeden önemli olan, genişletme durumunu yansıtmak üzere güncelleştirilmemesidir. ExpandPath çağrısı yaptığımı biliyorum çünkü istemciden gönderilen veri talebini ve her çağrı için sunucudan gelen verileri yanıt olarak expandPath'e götürebiliyorum. Ayrıca, seçili olan düğüm hakkında başka bir pencerede bilgi görüntüler ve doğru seçilmiş düğümü gösterir. Ama, benim hayal kırıklığım için, GUI sadece kök düğümünü (genişletilmiş) ve önceki genişletilmiş durum yerine (genişlemeyen) çocukları gösterir.

    Sorularım: JTree'imin genişletme durumunu nasıl geri yükleyebilirim, böylece GUI bir veri modeli güncellemesinden önce ve sonra aynı kalır?

    Bunlar denedim o şeylerden birkaçı şunlardır:

    • Ben equals() ve hashCode() geçersiz kılarak çözüldü mayın ve onun problemine benzer bir kurulum ile a thread buldum ama bu benim için işe yaramadı. setExpandsSelectedPaths(true), nodeStructureChanged(), genişleme durumuna tasarruf JTree.invalidate()
    • Birçok farklı varyasyonlar Ancak, ben doğru veri geri geçirilen görebileceğiniz gibi genişleme durumu yanlış inanıyoruz:
    • çeşitli metotlar gibi genişleme çağırmak için istemci uygulaması ve sunucu uygulaması arasında ileri ve geri. Eğer sağlayabilir herhangi bir yardım için şimdiden

      package tree.sscce; 
      import javax.swing.JFrame; 
      import javax.swing.JPanel; 
      import javax.swing.SwingUtilities; 
      import java.awt.BorderLayout; 
      import javax.swing.JScrollPane; 
      import javax.swing.JTree; 
      import javax.swing.JButton; 
      import java.util.Enumeration; 
      import javax.swing.BoxLayout; 
      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; 
      import java.awt.event.ActionListener; 
      import java.awt.event.ActionEvent; 
      import javax.swing.JTextPane; 
      
      public class TreeSSCCE extends JFrame implements TreeWillExpandListener { 
      
      private static final long serialVersionUID = -1930472429779070045L; 
      
      public static void main(String[] args) 
      { 
          SwingUtilities.invokeLater(new Runnable() { 
           public void run() { 
            TreeSSCCE inst = new TreeSSCCE(); 
            inst.setLocationRelativeTo(null); 
            inst.setVisible(true); 
            inst.setDefaultCloseOperation(EXIT_ON_CLOSE); 
           }   
          }); 
      } 
      
      private DefaultMutableTreeNode rootNode; 
      private JTree tree; 
      private DefaultTreeModel treeModel; 
      private TreePath selectionPathPriorToNewData; 
      private Enumeration<TreePath> expandedPathsPriorToNewData; 
      private int treeSize = 5; 
      
      public TreeSSCCE() { 
      
          this.setBounds(0, 0, 500, 400); 
          JPanel mainPanel = new JPanel(); 
          getContentPane().add(mainPanel, BorderLayout.CENTER); 
          mainPanel.setBounds(0, 0, 500, 400); 
          mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 
      
          JPanel descriptionPanel = new JPanel(); 
          descriptionPanel.setBounds(0, 0, 500, 200); 
          mainPanel.add(descriptionPanel); 
      
          JTextPane textPane = new JTextPane(); 
          String newLine = System.getProperty("line.separator"); 
          descriptionPanel.setLayout(new BorderLayout(0, 0)); 
          textPane.setText("Start by expanding some nodes then click 'Add New Data' and you will notice that the tree state is not retained."); 
          descriptionPanel.add(textPane); 
      
          // Initialize The Tree 
          tree = new JTree(); 
          rootNode = new DefaultMutableTreeNode("Root"); 
          treeModel = new DefaultTreeModel(rootNode); 
          tree.addTreeWillExpandListener(this); 
          tree.setModel(treeModel); 
          tree.setShowsRootHandles(true); 
          populateTree(false); 
      
          JScrollPane scrollPane = new JScrollPane(tree); 
          mainPanel.add(scrollPane); 
      
          JPanel buttonPanel = new JPanel(); 
          mainPanel.add(buttonPanel); 
      
          JButton btnAddNewData = new JButton("Add New Data"); 
          btnAddNewData.addActionListener(new ActionListener() { 
           public void actionPerformed(ActionEvent arg0) { 
            addNewDataToTree(); 
           } 
          }); 
          buttonPanel.add(btnAddNewData); 
      
      
      } 
      
      private void removeAllTreeNodes() 
      { 
      
          while(!treeModel.isLeaf(treeModel.getRoot())) 
          { 
           treeModel.removeNodeFromParent((MutableTreeNode)treeModel.getChild(treeModel.getRoot(),0)); 
          } 
          treeModel = null; 
          treeModel = new DefaultTreeModel(rootNode); 
          tree.setModel(treeModel); 
      } 
      
      public void restoreExpansionState(Enumeration enumeration) 
      { 
          if (enumeration != null) 
          { 
           while (enumeration.hasMoreElements()) 
           { 
            TreePath treePath = (TreePath) enumeration.nextElement(); 
            tree.expandPath(treePath); 
            tree.setSelectionPath(treePath); 
           } 
           tree.setSelectionPath(selectionPathPriorToNewData); 
          } 
      } 
      
      protected void addNewDataToTree() 
      { 
          // save the tree state 
          selectionPathPriorToNewData = tree.getSelectionPath(); 
          expandedPathsPriorToNewData = tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot())); 
          removeAllTreeNodes(); 
          populateTree(true); 
          restoreExpansionState(expandedPathsPriorToNewData); 
      } 
      
      private void populateTree(boolean newData) 
      { 
          if(newData) 
           treeSize++; 
          MyParentNode[] parents = new MyParentNode[treeSize]; 
          for(int i = 0; i < treeSize; i++) 
          { 
           parents[i] = new MyParentNode("Parent [" + i + "]"); 
           treeModel.insertNodeInto(parents[i], rootNode, i); 
          } 
      } 
      
      @Override 
      public void treeWillCollapse(TreeExpansionEvent evt) throws ExpandVetoException { 
          // Not used. 
      } 
      
      @Override 
      public void treeWillExpand(TreeExpansionEvent evt) throws ExpandVetoException 
      { 
          System.out.println("Tree expanding: " + evt.getPath()); 
          tree.setExpandsSelectedPaths(true); 
          tree.setSelectionPath(evt.getPath()); 
          // we have already loaded the top-level items below root when we 
          // connected so lets just return... 
          if(evt.getPath().getLastPathComponent().equals(treeModel.getRoot())) 
           return; 
      
          // if this is not root lets figure out what we need to do. 
          DefaultMutableTreeNode expandingNode = (DefaultMutableTreeNode) evt.getPath().getLastPathComponent(); 
      
          // if this node already has children then we don't want to reload so lets return; 
          if(expandingNode.getChildCount() > 0) 
           return;  
          // if this node has no children then lets add some 
          MyParentNode mpn = new MyParentNode("Parent Under " + expandingNode.toString()); 
          treeModel.insertNodeInto(mpn, expandingNode, expandingNode.getChildCount()); 
          for(int i = 0; i < 3; i++) 
          { 
           treeModel.insertNodeInto(new DefaultMutableTreeNode("Node [" + i + "]"), mpn, i); 
          } 
      } 
      
      private class MyParentNode extends DefaultMutableTreeNode 
      { 
          private static final long serialVersionUID = 433317389888990065L; 
          private String name = ""; 
      
          public MyParentNode(String _name) 
          { 
           super(_name); 
           name = _name; 
          } 
      
          @Override 
          public int hashCode() { 
           final int prime = 31; 
           int result = 1; 
           result = prime * result + getOuterType().hashCode(); 
           result = prime * result + ((name == null) ? 0 : name.hashCode()); 
           return result; 
          } 
      
          @Override 
          public boolean equals(Object obj) { 
           if (this == obj) 
            return true; 
           if (obj == null) 
            return false; 
           if (getClass() != obj.getClass()) 
            return false; 
           MyParentNode other = (MyParentNode) obj; 
           if (!getOuterType().equals(other.getOuterType())) 
            return false; 
           if (name == null) { 
            if (other.name != null) 
             return false; 
           } else if (!name.equals(other.name)) 
            return false; 
           return true; 
          } 
      
          @Override 
          public boolean isLeaf() 
          { 
           return false; 
          } 
      
          private TreeSSCCE getOuterType() { 
           return TreeSSCCE.this; 
          }  
      } 
      
      } 
      

      Teşekkür:

    İşte benim SSCCE olduğunu.

    P.S. Bu benim ilk sorum, bu yüzden lütfen doğru bir şekilde sorduğumda lütfen bana bildirin (ve benim için kolay;)).

  • +0

    Wow, bir sürü yararlı bilgi için Vay! Eski düğümlerden yola çıkarak yeni düğümleri kullanarak bir ağaç yolunu yeniden yapılandırmanız gerekeceğinden şüpheleniyorum. Her bir düğümü tanımlamanın bir yolunun olduğunu mu sanıyorsun? Tüm genişletilmiş yolları temsil eden basit bir 'String' (örneğin) oluşturun. Ağacı güncellemeye geldiğinizde, bu 'String' yollarını kullanarak, mevcut düğümlerden yeni ağaç yolları oluşturun ... – MadProgrammer

    +1

    "FileTreeModel", [burada] alıntı yaptı (http://stackoverflow.com/a/14837208/230513) Sorunu ortadan kaldırmazsa, kodunuzu basitleştirebilir. – trashgod

    +0

    @trashgod 'FileTreeModel', benim düğümlerim, dosya hakkında bilgi ve uygulamaya özel bilgiler içeren özel nesneler olduğundan benim için çalışmaz. Ayrıca, istemci uygulamam, sunucuda bulunan bu dosyaya doğrudan erişemez. – Jeremy

    cevap

    1

    Bunu işlemek için özel bir ağaç modeli (DefaultTreeModel'i genişletir) ve DBTreeEvent.STRUCTURE_CHANGED olayında tepki veriyorum. Eski devleti korumak için yaptığım şey budur. Size yardım edip etmeyeceğinden emin de değil ..

    //NOTE: node is the tree node that caused the tree event 
    TreePath nodesPath = new TreePath(node.getPath()); 
    TreePath currentSel = myTree.getLeadSelectionPath(); 
    List<TreePath> currOpen = getCurrExpandedPaths(nodesPath); 
    super.nodeStructureChanged(node); 
    reExpandPaths(currOpen); 
    myTree.setSelectionPath(currentSel); 
    
    private List<TreePath> getCurrExpandedPaths(TreePath currPath) 
    { 
        List<TreePath> paths = new ArrayList<TreePath>(); 
        Enumeration<TreePath> expandEnum = myTree.getExpandedDescendants(currPath); 
        if (expandEnum == null) 
         return null; 
    
        while (expandEnum.hasMoreElements()) 
         paths.add(expandEnum.nextElement()); 
    
        return paths; 
    } 
    
    private void reExpandPaths(List<TreePath> expPaths) 
    { 
        if(expPaths == null) 
         return; 
        for(TreePath tp : expPaths) 
         myTree.expandPath(tp); 
    }