2011-01-17 7 views
11

कुछ समय पहले मैंने this question से पूछा था। सभी समाधान कामकाज हैं।क्या जेएलिस्ट के लिए स्विंग के एमवीसी कार्यान्वयन में कुछ गड़बड़ है?

अब यह नहीं हो सकता है। मुझे लगता है कि यहां कुछ गड़बड़ है, लेकिन मैं यह नहीं बता सकता कि यह स्विंग का एमवीसी मॉडल है जो अवधारणात्मक रूप से गलत है, या यदि यह मेरी सोच है जो अवधारणात्मक रूप से गलत है।

यहां समस्या फिर से है। मैं दस्तावेज़ के पृष्ठों के लिए थंबनेल की सूची लागू करने के लिए JList का उपयोग कर रहा हूं। यदि उपयोगकर्ता सूची से कोई अन्य थंबनेल चुनता है, तो वह पृष्ठ लोड हो जाता है। ऐसा करने के लिए मैंने को JList पर जोड़ा, जब चयन में परिवर्तन होता है, तो वह उस पृष्ठ को लोड करता है। लेकिन उपयोगकर्ता दूसरे नियंत्रण का उपयोग कर पेज भी बदल सकता है। स्वाभाविक रूप से, मैं चाहता हूं कि यह पृष्ठ यहां चुने गए थंबनेल सूची में दिखाई दे। तो JList अद्यतन करने के लिए मैं setSelectedIndex()। दुर्भाग्यवश इसका ListSelectionEvent बढ़ाने का अवांछित प्रभाव है जो श्रोता को पृष्ठ को फिर से लोड करने का कारण बनता है।

अब क्या गलत है? मैंने मॉडल को कहीं और से बदल दिया है, इसलिए स्वाभाविक रूप से मैं दृश्य को स्वयं अपडेट करना चाहता हूं, लेकिन मैं नहीं चाहता कि यह ईवेंट ट्रिगर करे। स्विंग एमवीसी सही लागू नहीं कर रहा है? या क्या मैं यहाँ एक बिंदु खो रहा हूँ?

+0

महान जवाब के लिए धन्यवाद हर कोई!मैंने @ ब्रिटिशमत्त के जवाब को स्वीकार किया, क्योंकि यह सबसे विस्तृत और अंतर्दृष्टिपूर्ण है और इसमें सबसे साफ समाधान है। समस्या यह है कि पृष्ठ को लोड करने वाला घटक यह देखना चाहिए कि उसे उसी पृष्ठ को लोड करने का अनुरोध किया गया था और इसे नहीं करना चाहिए। लिंक बहुत उपयोगी थे। मुझे अभी भी लगता है कि स्विंग का एमवीसी मॉडल दोषपूर्ण है। उन्हें पारंपरिक तरीके से जाना चाहिए था। उनके मॉडल की तुलना में उनका मॉडल अधिक परेशानी प्रतीत होता है। –

+0

मुझे कई बार श्रोता अपडेट के साथ एक ही समस्या का सामना करना पड़ा है। कल्पना करें कि क्या आपके पास एन घटक हैं जिन्हें एक-दूसरे को अपडेट करना है ... भले ही आप एक वास्तविक प्रदर्शन परिवर्तन की जांच करें, यह तय करने के लिए कि किसी ईवेंट को आग लगाना है या नहीं, तो एन-1 घटकों को अन्य एन -1 घटकों से निकाल दिया जाएगा वे अद्यतन हो जाते हैं। – Timmos

उत्तर

9

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

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

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

+0

मैं विस्तृत उत्तर की सराहना करता हूं; यह बहुत अंतर्दृष्टि देता है। मुझे डर था कि मैं अकेला ही इस समस्या का सामना कर रहा था, और यह मुझे परेशान कर रहा था क्योंकि यह दो बार फिर से दिखाई दिया है। पिछले पैराग्राफ में आप जो सुझाव देते हैं वह पहले क्या हो रहा था। लेकिन जब यह एक अनंत लूप में नहीं गया, तब भी यह पृष्ठ को दो बार लोड कर दिया। मुझे इन सभी घटनाओं को जगह भर में उड़ना भी पसंद नहीं है। कम से कम मुझे खुशी है कि यह एक सामान्य समस्या है, और अब मुझे कम बेवकूफ़ लगता है। –

0

आम तौर पर श्रोता काम करने का तरीका यह है कि जब भी यह इंतजार कर रहा है, तो यह हर बार "बंद हो जाएगा"। अगर मुझे लगता है कि यह चीजों के अपने पक्ष से गलतफहमी है।

3

स्विंग बिल्कुल एमवीसी नहीं है, लेकिन इसकी एमवीसी में जड़ें हैं (अंतर में तथ्य यह है कि स्विंग में दृश्य और नियंत्रक अन्य एमवीसी की तुलना में अधिक निकटता से संबंधित हैं Swing architecture अधिक जानकारी के लिए)।

लेकिन यह समस्या का सामना नहीं कर रहा है। ऐसा लगता है कि आपको इवेंट श्रोताओं में ईवेंट के प्रकार के लिए मान्य करना होगा और यह तय करना होगा कि इसे अनदेखा करना है या नहीं: यदि ईवेंट की उत्पत्ति सूची में हुई थी तो इसे बदलें। अगर किसी अन्य नियंत्रण से ट्रिगर किया गया था, तो मत करो।

+0

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

+2

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

5

यह व्यवहार की उम्मीद है।

Model-View-Controller [Wikipedia] से:

घटना पर ही आधारित प्रणालियों में, मॉडल पर्यवेक्षकों (आमतौर पर देखा गया) इसकी सूचना देता जानकारी बदल जाती है ताकि वे प्रतिक्रिया कर सकते हैं।

इसलिए, जब आप JList पर setSelectedIndex कहते हैं, आप अपने मॉडल है, जो उसके बाद प्रत्येक ListSelectionListener सूचित करता है अद्यतन कर रहे हैं। यह एमवीसी नहीं होगा यदि आप बिना किसी बताए मॉडल को "चुपचाप" अपडेट कर सकते हैं।

+0

ग्रेट उद्धरण! तुम पूरी तरह ठीक हो। लेकिन अब जब मैं इसके बारे में सोचता हूं, तो जेएलिस्ट एक दृश्य है, इसलिए इसे अपडेट करना होगा। लेकिन ListSelectionListener एक दृश्य नहीं है। यह एक नियंत्रक है। तो मुझे लगता है कि यह समस्या है। @OscarRyz की तरह कहा, नियंत्रक और दृश्य बारीकी से संबंधित हैं। असल में, नियंत्रक मॉडल के साथ मिलकर है। अजीब! क्योंकि नियंत्रक को उपयोगकर्ता क्रियाओं को सुनना चाहिए (जैसे किसी अन्य आइटम पर क्लिक करना), मॉडल में बदलाव नहीं। तो मुझे लगता है कि यह समस्या है। AddListSelectionListener() के बजाय, इस तरह की किसी चीज़ का addItemClickedListener() होना चाहिए। –

2

क्या @ डोगबेन ने कहा।

लेकिन समस्या को ठीक करने के लिए आपको श्रोता के दौरान कुछ प्रकार की राज्य जांच जोड़ने की आवश्यकता है ताकि यह देखने के लिए कि घटना एक है जिसे आपको अनदेखा करना चाहिए। ListSelectionEvent में getValueAdjusting() विधि है, लेकिन यह ज्यादातर आंतरिक है। आपको जो करना है वह स्वयं को अनुकरण करें।

तो उदाहरण के लिए जब आप बाहरी चयन से सूची अपडेट करते हैं तो आपके पास कोड होगा ...

try { 
    setSelectionAdjusting(true); 
    /* ... your old update code ... */ 
} finally { 
    setSelectionAdjusting(false); 
} 

और अद्यतन कोड में ListSelectionListenerEvent

public void valueChanged(ListSelectionEvent e) { 
    if (!isSelectionAdjusting()) { 
     /* ... do what you did before ...*/ 
    } 
} 

Scoping और उपयोग मुद्दों के लिए पाठक के लिए एक व्यायाम के रूप में छोड़ दिया जाता है। आपको setSelectionAdjusting लिखना होगा, और संभवतः इसे अन्य ऑब्जेक्ट्स पर भी सेट करना होगा।

+0

मुझे एक और हैक की तरह लगता है। मुझे अभी भी लगता है कि यहां कुछ अवधारणात्मक रूप से गलत है। –

2

मुझे अभी भी लगता है कि यहां कुछ अवधारणात्मक रूप से गलत है।

मैं सहानुभूति है, लेकिन यह विचार करने के लिए है कि आप एक सरल JList एक ListSelectionModel को देख नहीं है मदद मिल सकती है। इसके बजाए, आपके पास JList और हाइब्रिड चयन मॉडल का निरीक्षण करने वाला कुछ अन्य नियंत्रण है। @Taisin's example में, हाइब्रिड CustomSelectionModel है जो DefaultListSelectionModel बढ़ाता है और चुप परिवर्तनों की अनुमति देता है। संगत होने पर, इस मॉडल को साझा करना भी संभव है, जैसा कि question & answer और ट्यूटोरियल से यह SharedModelDemo में सुझाया गया है।

के लिए, इस thread लेख Java SE Application Design With MVC: Issues With Application Design है, जो और अधिक विस्तार में मुद्दे को संबोधित हवाला दिया है।

+0

सहानुभूति के लिए धन्यवाद! हाँ, मुझे लगता है कि यह सबसे साफ समाधान लगता है। लेकिन अगर आप इसके बारे में सोचते हैं तो ऐसा लगता है कि आप स्विंग मॉडल में उस वैचारिक त्रुटि को हल कर रहे हैं। आपके द्वारा उल्लेख किए गए लेख में, यह चरण 3 है: 'मॉडल अपडेट किया गया है। यह अपनी संपत्ति परिवर्तन के नियंत्रक को सूचित करता है। 'यह एमवीसी नहीं है। मॉडल कभी नियंत्रक को सूचित नहीं करता है। यह दृश्य को सूचित करता है। अपडेट फेंकने के लिए मॉडल को ओवरराइट करके, आप चरण 3 पर मौजूद इस बग को प्रभावी ढंग से ठीक करते हैं। –

+0

आप सही हैं, यह शुद्ध एमवीसी नहीं है; यह एक _separable मॉडल architecture_ है, @OscarRyz द्वारा उद्धृत: http://java.sun.com/products/jfc/tsc/articles/architecture/#separable – trashgod

+0

और यहां तक ​​कि यहां स्पष्ट भी मुझे लगता है: http://www.oracle.com /technetwork/articles/javase/index-142890.html#3 मुझे नहीं पता कि उन्होंने इस डिज़ाइन को क्यों चुना है। उनका कारण यह है कि "इस संशोधित एमवीसी का उपयोग मॉडल को दृश्य से पूरी तरह से खत्म करने में मदद करता है।" लेकिन यह अच्छा क्यों है? यह किस समस्या को हल करता है? फिलहाल, मेरे लिए यह एक परेशानी का लगता है। –

2

मैं हमेशा इस तरह कार्य करें:

public class MyDialog extends JDialog { 
     private boolean silentGUIChange = false; 

    public void updateGUI { 
     try { 
      silenGUIChange = true; 

      // DO GUI-Updates here: 
      textField.setText("..."); 
      checkBox.setSelected (...); 

     } 
     finally { 
      silentGUIChange = false; 
     } 
    } 

    private void addListeners() { 
     checkBox.addChangeListener (new ChangeListener() { 
      public void stateChanged (ChangeEvent e) { 
       if (silentGUIChange) 
       return; 

       // update MODEL 
       model.setValue(checkBox.isSelected()); 
      } 
     }); 
    } 

} 
संबंधित मुद्दे