2013-02-22 92 views
5

मेरे पास एक ऐसा एप्लिकेशन है जिसमें एक डिफ़ॉल्ट ट्रीमोडेल के साथ समर्थित एक जेटी है जिसमें फाइलों का पदानुक्रम प्रदर्शित करने के लिए उपयोग किया जाता है जो मेरे सर्वर पर फ़ाइल सिस्टम के एक सेक्शन को दर्शाता है (मैं इसका उल्लेख करूंगा यह मेरे क्लाइंट ऐप) के रूप में है। मेरे पास एक सर्वर एप्लिकेशन भी है जो डेटा प्रदान करता है जो मेरे क्लाइंट ऐप को प्रदर्शित करने की आवश्यकता है (मैं इसे अपने सर्वर ऐप के रूप में संदर्भित करता हूं)। मैं एक "आलसी लोड बच्चों" दृष्टिकोण का उपयोग कर रहा हूं ताकि उपयोगकर्ता को केवल मेरे पेड़ में फाइल लोड करनी पड़े, यदि उपयोगकर्ता में रुचि है। आलसी लोड दृष्टिकोण:आलसी लोडिंग के साथ जेटी में विस्तार/चयन राज्य

  1. मैं ओवरराइड treeWillExpand(TreeExpansionEvent evt)
  2. मैं विस्तार हो रहा नोड के कि होने के लिए चयन पथ सेट।
  3. फिर मैं उस नोड के बच्चों से पूछने वाले सर्वर को एक संदेश भेजता हूं।
  4. जब सर्वर प्रतिसाद देता है तो मुझे अंतिम चयनित पथ घटक मिलता है।
  5. फिर मैं प्रत्येक लौटाई गई डेटा फ़ाइलों के लिए DefaultTreeModel.insertNodeInto() का उपयोग करता हूं।
  6. अंततः मैं DefaultTreeModel.nodeStructureChanged() पर कॉल करता हूं।

उपर्युक्त काम ठीक है और मुझे बच्चों को आलसी लोड करने में कोई समस्या नहीं है। मेरी समस्या तब आती है जब सर्वर पर नया डेटा अपलोड किया जाता है और मैं न केवल नए डेटा को शामिल करने के लिए पेड़ को अपडेट करना चाहता हूं, बल्कि विस्तार स्थिति और चयनित नोड को पेड़ को अपडेट करने से पहले क्या था (ताकि उपयोगकर्ता पेड़ पर चारों ओर झटका नहीं है क्योंकि देखने के लिए नया डेटा है)।

  • सर्वर अनुप्रयोग अभिलेखागार इस डेटा

    1. नए डेटा सर्वर पर अपलोड किया जाता है और अपलोड की गई फ़ाइलों के बारे में जानकारी के साथ एक डेटाबेस भरता है: प्रवाह इस प्रकार है।
    2. सर्वर ऐप क्लाइंट ऐप को सूचित करता है कि नया डेटा अपलोड किया गया था।
    3. क्लाइंट एप्लिकेशन का पेड़ JTree.getExpandedDescendants()
    4. क्लाइंट एप्लिकेशन का उपयोग करने के विस्तार के राज्य वृक्ष JTree.getSelectionPath()
    5. क्लाइंट एप्लिकेशन का उपयोग करने के चयन के पथ DefaultTreeModel से सभी नोड्स को हटा बचाता है बचाता है।
    6. क्लाइंट ऐप रूट नोड से शुरू होने वाले सर्वर से डेटा का अनुरोध करता है।
    7. क्लाइंट ऐप JTree.getExpandedDescendants() से JTree.expandPath() पर गणना के पेड़ पथ गणना को वापस चलाता है, जिसमें प्रत्येक ट्रीपाथ पर गणना होती है।
    8. क्लाइंट ऐप चयनित पेड़ पथ सेट करता है।

    मेरी समस्या यह है कि कोई फर्क नहीं पड़ता कि मैं पेड़ के जीयूआई का प्रयास करता हूं, विस्तार राज्य को प्रतिबिंबित करने के लिए अद्यतन नहीं किया जाता है। मुझे पता है कि विस्तार करने के लिए मेरा कॉल काम कर रहा है क्योंकि मैं क्लाइंट से भेजे गए डेटा के लिए अनुरोध देख सकता हूं और विस्तार से प्रत्येक कॉल के लिए सर्वर से डेटा के साथ प्रतिक्रिया देख सकता हूं। मैं वर्तमान में चयनित नोड के बारे में अन्य विंडो में जानकारी भी प्रदर्शित करता हूं और यह सही ढंग से चयनित नोड दिखा रहा है। लेकिन, हां, मेरी निराशा के लिए, जीयूआई केवल पिछले विस्तारित राज्य की बजाय रूट नोड (विस्तारित) और उसके बच्चों (विस्तारित नहीं) को प्रदर्शित करता है।

    तो मेरा प्रश्न है: मैं अपने जेटीआर की विस्तार स्थिति को कैसे पुनर्स्थापित कर सकता हूं ताकि जीयूआई डेटा मॉडल अपडेट से पहले और बाद में समान रहे?

    इन चीजों में से कुछ है कि मैं कोशिश की है इस प्रकार हैं:

    • मैं मेरा और उसकी समस्या के लिए एक समान सेटअप के साथ a thread पाया equals() और hashCode() अधिभावी द्वारा हल किया गया था, लेकिन यह मेरे लिए काम नहीं किया। setExpandsSelectedPaths(true), nodeStructureChanged(), JTree.invalidate()
    • विस्तार राज्य बचत पर कई अलग अलग रूपों, हालांकि, मैं नहीं मानता कि विस्तार अवस्था गलत है मैं देख सकता हूँ सही डेटा वापस पारित किया जा रहा:
    • विभिन्न तरीकों जैसे विस्तार आह्वान करने के लिए और आगे क्लाइंट ऐप और सर्वर ऐप के बीच।

      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; 
          }  
      } 
      
      } 
      

      किसी भी मदद प्रदान कर सकते हैं के लिए अग्रिम धन्यवाद:

    यहाँ मेरी SSCCE है।

    पीएस); यह मेरा पहला सवाल तो मुझे पता है कि अगर मैं ठीक से पूछ रहा हूँ चलो (और यह मुझ पर आसान लेने के लिए) कृपया है।

  • +0

    वाह, बहुत उपयोगी जानकारी के लिए +1, +1! मुझे लगता है कि आप पुराने नोड्स पर आधारित नई नोड्स का उपयोग कर एक पेड़ के पथ को फिर से संगठित करने के लिए जा रहे हैं,। मुझे लगता है कि आपके पास प्रत्येक नोड को पहचानने का कोई तरीका है? उत्पन्न एक सरल 'स्ट्रिंग' (उदाहरण के लिए), है कि सभी का विस्तार पथ का प्रतिनिधित्व करता है। जब आप पेड़ को अपडेट करने के लिए आते हैं, तो इन 'स्ट्रिंग' पथों का उपयोग करके, उपलब्ध नोड्स से नए पेड़ पथ बनाएं ... – MadProgrammer

    +1

    'FileTreeModel' उद्धृत [यहां] (http://stackoverflow.com/a/14837208/230513) समस्या को खत्म न करने पर, आपके कोड को सरल बना सकते हैं। – trashgod

    +0

    @trashgod 'FileTreeModel' मेरे लिए काम नहीं करेगा क्योंकि मेरे नोड्स कस्टम ऑब्जेक्ट्स हैं जिनके पास फ़ाइल के साथ-साथ एप्लिकेशन विशिष्ट जानकारी के बारे में जानकारी है। साथ ही, मेरे क्लाइंट ऐप को सर्वर पर रहने के रूप में इन फ़ाइलों तक सीधे पहुंच नहीं है। – Jeremy

    उत्तर

    1

    मैं एक कस्टम पेड़ मॉडल (DefaultTreeModel फैली) का उपयोग कर रहा हूँ और DBTreeEvent.STRUCTURE_CHANGED स्थिति में प्रतिक्रिया इस संभालने के लिए। पुराने राज्य को संरक्षित करने के लिए मैं यही करता हूं। सुनिश्चित नहीं है कि यह आपकी मदद करेगा या नहीं ..

    //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); 
    }