2010-05-25 14 views
5

मेरी "समस्या" निम्नलिखित द्वारा वर्णित की जा सकती है। मान लें कि हमारे पास एक गहन प्रक्रिया है जिसे हम पृष्ठभूमि में चलाना चाहते हैं और इसे स्विंग जेपी प्रोग्रेस बार अपडेट करना है। समाधान आसान है:स्विंगवर्कर के अन्य तरीकों से प्रकाशित करने के लिए कैसे

import java.util.List; 

import javax.swing.JOptionPane; 
import javax.swing.JProgressBar; 
import javax.swing.SwingWorker; 


/** 
* @author Savvas Dalkitsis 
*/ 
public class Test { 

    public static void main(String[] args) { 
     final JProgressBar progressBar = new JProgressBar(0,99); 
     SwingWorker<Void, Integer> w = new SwingWorker<Void, Integer>(){ 

      @Override 
      protected void process(List<Integer> chunks) { 
       progressBar.setValue(chunks.get(chunks.size()-1)); 
      } 

      @Override 
      protected Void doInBackground() throws Exception { 

       for (int i=0;i<100;i++) { 
        publish(i); 
        Thread.sleep(300); 
       } 

       return null; 
      } 

     }; 
     w.execute(); 
     JOptionPane.showOptionDialog(null, 
       new Object[] { "Process", progressBar }, "Process", 
       JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, 
       null, null, null); 
    } 

} 

अब मान लें कि मेरे पास लंबे समय तक कई विधियां हैं। उदाहरण के लिए हमारे पास एक तरीका है जो सर्वर से फ़ाइल डाउनलोड करता है। या कोई अन्य जो सर्वर पर अपलोड करता है। या वास्तव में कुछ भी। उन तरीकों से प्रकाशित विधि को प्रस्तुत करने का सही तरीका क्या है ताकि वे उचित रूप से जीयूआई अपडेट कर सकें?

मैं अब तक क्या पाया है यह है (मान लेते हैं कि विधि "aMethod" उदाहरण के लिए कुछ अन्य पैकेज में रहता है):

import java.awt.event.ActionEvent; 
import java.util.List; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JOptionPane; 
import javax.swing.JProgressBar; 
import javax.swing.SwingWorker; 


/** 
* @author Savvas Dalkitsis 
*/ 
public class Test { 

    public static void main(String[] args) { 
     final JProgressBar progressBar = new JProgressBar(0,99); 
     SwingWorker<Void, Integer> w = new SwingWorker<Void, Integer>(){ 

      @Override 
      protected void process(List<Integer> chunks) { 
       progressBar.setValue(chunks.get(chunks.size()-1)); 
      } 

      @SuppressWarnings("serial") 
      @Override 
      protected Void doInBackground() throws Exception { 

       aMethod(new AbstractAction() { 

        @Override 
        public void actionPerformed(ActionEvent e) { 
         publish((Integer)getValue("progress")); 
        } 
       }); 

       return null; 
      } 

     }; 
     w.execute(); 
     JOptionPane.showOptionDialog(null, 
       new Object[] { "Process", progressBar }, "Process", 
       JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, 
       null, null, null); 
    } 

    public static void aMethod (Action action) { 
     for (int i=0;i<100;i++) { 
      action.putValue("progress", i); 
      action.actionPerformed(null); 
      try { 
       Thread.sleep(300); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

यह काम करता है, लेकिन मैं यह कुछ का अभाव है पता है। कोई विचार?

उत्तर

0

शायद प्रत्येक लंबी विधि के लिए एक स्विंगवर्कर करें। प्रत्येक स्विंगवर्कर का अपना प्रगति स्तर होता है।

प्रत्येक स्विंगवर्कर डिनबैकग्राउंड विधि के दौरान अपने स्वयं के प्रगति स्तर को अपडेट करता है, फिर प्रकाशित कॉल करें। प्रक्रिया विधि के अंदर, इसलिए ईडीटी के अंदर, प्रत्येक स्विंगवर्कर ने इसका प्रगति स्तर पढ़ा, और मॉडल और दृष्टि सामान्य प्रगति पट्टी को अपडेट किया।

+0

क्या होगा यदि हमारे पास केवल एक भयानक लंबी विधि है? मैं डाउनवॉटिंग नहीं कर रहा हूं, लेकिन यह समाधान नहीं है – Xorty

+0

यदि मेरा उत्तर खराब है तो आप डाउनवोटिंग कर सकते हैं। लेकिन मैंने सवाल में पढ़ा "उदाहरण के लिए हमारे पास एक तरीका है जो किसी सर्वर से फ़ाइल डाउनलोड करता है या कोई अन्य जो सर्वर पर अपलोड करता है। या वास्तव में कुछ भी।" ... तो मुझे लगता है कि बहुत सारी विधियां हैं, न केवल एक भयानक लंबा ? – Istao

+0

मेरी समस्या यह है कि कोड के विभिन्न हिस्सों से इन विधियों को बुलाया जा सकता है। और गुई तत्व को ताज़ा करने की आवश्यकता होगी, वह हमेशा एक जैसा नहीं होगा। मेरे समाधान के साथ मैं एक सामान्य विधि बना सकता हूं और हर बार जब मैं एक नया स्विंगवर्कर बनाता हूं तो मैं अपने गुई पर प्रक्रिया विधि का आकलन कर सकता हूं। –

0

मुझे इसी तरह की समस्या का सामना करना पड़ा। अगर हम पुनरावृत्तियों की बहुत कुछ है, हम doInBackGround() विधि में प्रगति बार अद्यतन कर सकते हैं

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

तीसरे बिंदु में मैंने वर्णन किया कि विधि से थ्रेड को कैसे कार्यान्वित किया जाए जो कुछ कार्य पूरा करता है जो कम से कम हमारे जावा कोड में नहीं है (और कम से कम हमारे जावा कोड में नहीं) और बाधित नहीं किया जा सकता है। थ्रेड अपडेट जेपी प्रोग्रेसबार जिसे विधि पैरामीटर के रूप में दिया गया था। यह, हालांकि, definitelly धीमी के रूप में शुद्ध विधि बुला

10

(मैं इसे और अधिक स्पष्ट और सामान्यीकृत बनाने के लिए मेरा उत्तर अद्यतन करने हूँ) यद्यपि आप को सफलतापूर्वक अपने तर्क और प्रस्तुति decoupled है, यह में किया नहीं कर रहा है एक तरीका है जो कोड पुन: उपयोग करने के लिए खुद को उधार देता है।जावा का PropertyChangeSupportbound properties लागू करके प्रस्तुति से तर्क को डीक्यूपल करना आसान बनाता है, और कुछ पर्याप्त पुन: उपयोग प्राप्त करता है। विचार कार्रवाई वस्तुओं के बजाय घटना हैंडलर का उपयोग करना है।

सबसे पहले, अमूर्तता को संकल्पना दें। पृष्ठभूमि कार्य को जीयूआई को "चिल्लाओ" (प्रकाशित) करने की आवश्यकता है, और जीयूआई को इसके लिए सुनने की जरूरत है। दो सामान्य वर्ग इस विचार को संहिताबद्ध करेंगे:

/** 
* Wrapper for the background logic. 
* 
* <T> return type 
* <S> intermediary type (the "shout out") 
*/ 
public static abstract class LoudCall<T, S> implements Callable<T> { 

    private PropertyChangeSupport pcs; 
    private S shout; 

    public LoudCall() { 
     pcs = new PropertyChangeSupport(this); 
    } 

    public void shoutOut(S s) { 
     pcs.firePropertyChange("shoutOut", this.shout, 
       this.shout = s); 
    } 

    public void addListener(PropertyChangeListener listener) { 
     pcs.addPropertyChangeListener(listener); 
    } 

    public void removeListener(PropertyChangeListener listener) { 
     pcs.removePropertyChangeListener(listener); 
    } 

    @Override 
    public abstract T call() throws Exception; 
} 

/** 
* Wrapper for the GUI listener. 
* 
* <T> return type 
* <S> intermediary type (the "shout out" to listen for) 
*/ 
public static abstract class ListenerTask<T, S> extends SwingWorker<T, S> 
     implements PropertyChangeListener { 

    private LoudCall<T, S> aMethod; 

    public ListenerTask(LoudCall<T, S> aMethod) { 
     this.aMethod = aMethod; 
    } 

    @Override 
    protected T doInBackground() throws Exception { 
     aMethod.addListener(this); 
     return aMethod.call(); 
    } 

    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     if ("shoutOut".equals(evt.getPropertyName())) { 
      publish((S)evt.getNewValue()); 
     } 
    } 

    @Override 
    protected abstract void process(List<S> chunks); 
} 

ये कक्षाएं आपके सभी स्विंग विजेट्स के लिए उपयोग की जा सकती हैं। एक ProgressBar के लिए, "के बारे में बताने" एक पूर्णांक हो जाएगा, और वापसी प्रकार शून्य है:

public class ProgressExample { 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
    @Override 
    public void run() { 

     // 1. setup the progress bar 
     final JProgressBar progressBar = new JProgressBar(0, 99); 

     // 2. Wrap the logic in a "Loud Call" 
     LoudCall<Void, Integer> aMethod = new LoudCall<Void, Integer>() { 
      @Override 
      public Void call() throws Exception { 
       for (int i = 0; i < 100; i++) { 
        // "i have an update for the GUI!" 
        shoutOut(i); 
        Thread.sleep(100); 
       } 
       return null; 
      } 
     }; 

     // 3. Run it with a "Listener Task" 
     (new ListenerTask<Void, Integer>(aMethod) { 
      @Override 
      protected void process(List<Integer> chunks) { 
       progressBar.setValue(chunks.get(chunks.size() - 1)); 
      } 
     }).execute(); 

     // 4. show it off! 
     JOptionPane.showOptionDialog(null, 
      new Object[] { "Process", progressBar }, "Process", 
      JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, 
      null, null, null 
     ); 
    } 
     }); 
    } 
} 

केवल श्रोता जीयूआई विवरण के बारे में कुछ भी पता करने की जरूरत है, और पृष्ठभूमि तर्क अभी भी प्रकाशन पर नियंत्रण (है परोक्ष रूप से, "चिल्लाओ" द्वारा)। यह कोड अधिक terse, पठनीय, और पुन: प्रयोज्य है।

मुझे एहसास है कि यह सवाल अब बहुत पुराना है, लेकिन उम्मीद है कि यह किसी की मदद करेगी!

+1

यह समझना मुश्किल है कि यह उत्तर कितना उपयोगी है। यह फिर से पढ़ना पुरस्कार! – Arvanem

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