2012-06-16 24 views
5

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

public class MyView extends JPanel implements ActionListener { 
    private final MyController controller = new MyController(); 

    @Override public void actionPerformed(ActionEvent e) { 
    this.controller.updateOtherView(); 
    } 
} 

यह अनिवार्य रूप से मैं चाहता हूं, लेकिन यह समाप्त हो रहा है।

public class MyView extends JPanel implements ActionListener { 
    private MyController controller = new MyController(); 
    private OtherView otherView; 

    public MyView(MyOtherView otherView) { 
    this.otherView = otherView; 
    } 

    @Override public void actionPerformed(ActionEvent e) { 
    this.controller.updateOtherView(otherView); 
    } 
} 

और आप देख सकते हैं कि विचारों को अपडेट करने की वृद्धि हुई है और कक्षाओं है कि इस वृद्धि लग की संख्या की जरूरत है कि की संख्या के रूप में, विचार अनिवार्य रूप से वैश्विक चर रहे हैं और कोड जटिल और अस्पष्ट हो जाता है। एक और समस्या जो मैं चल रहा हूं वह यह है कि यह अन्य दृश्य आमतौर पर माईव्यू में सीधे नहीं जाता है, लेकिन इसे माईव्यू के माता-पिता के माध्यम से माईव्यू पर जाने के लिए जाना पड़ता है, जो वास्तव में मुझे बस खराब करता है।

इसका असली उदाहरण के लिए, मान लें कि मेरे पास मेनू और यह MyView है। MyView में एक प्ले बटन है, जो कुछ समय के लिए कुछ संगीत बजाता है और जब तक संगीत समाप्त नहीं हो जाता है तब तक प्ले बटन को अक्षम (ग्रेज़ आउट) करता है। अगर मेरे पास प्ले नामक मेनू विकल्प है, तो अब मुझे अन्य दृश्यों के प्ले बटन तक पहुंचने की ज़रूरत है, इसलिए मैं इसे भूरे रंग से बाहर कर सकता हूं। मैं हर जगह विचारों के इस कष्टप्रद गुजरने के बिना ऐसा कैसे कर सकता हूं? यद्यपि इस समस्या के लिए विशिष्ट समाधान हो सकते हैं, मैं कुछ ऐसा ढूंढ रहा हूं जो सामान्य मामले में इस दृश्य पहुंच समस्या को हल करेगी।

मुझे यकीन नहीं है कि इसे कैसे ठीक किया जाए। मैं एमवीसी पैटर्न का उपयोग किए बिना एमवीसी पैटर्न शब्दावली का उपयोग कर रहा हूं, जो आवश्यक हो सकता है या नहीं भी हो सकता है। किसी भी मदद की सराहना की है।

+0

कृपया मेरे उत्तर के साथ-साथ कोड उदाहरण में भी देखें। –

उत्तर

1

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

12

एक समाधान: बस नियंत्रक मॉडल को अपडेट करें। फिर मॉडल से जुड़े श्रोताओं ने विचारों को अपडेट किया। आप JMenuItems और संबंधित JButtons भी एक ही क्रिया साझा कर सकते हैं, और इस प्रकार जब आप क्रिया को अक्षम करते हैं तो यह उस क्रिया का उपयोग करने वाले सभी बटन/मेनू/आदि को अक्षम कर देगा।

उदाहरण के लिए, मुख्य वर्ग:

import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 

public class MvcExample { 

    private static void createAndShowGui() { 
     MyView view = new MyView(); 
     MyMenuBar menuBar = new MyMenuBar(); 
     MyModel model = new MyModel(); 
     MyControl control = new MyControl(model); 
     control.addProgressMonitor(view); 
     control.addView(view); 
     control.addView(menuBar); 

     model.setState(MyState.STOP); 

     JFrame frame = new JFrame("MVC Example"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(view.getMainPanel()); 
     frame.setJMenuBar(menuBar.getMenuBar()); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 

    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 

    private static final byte[] DATA_ARRAY = { 0x43, 0x6f, 0x70, 0x79, 0x72, 
     0x69, 0x67, 0x68, 0x74, 0x20, 0x46, 0x75, 0x62, 0x61, 0x72, 0x61, 
     0x62, 0x6c, 0x65, 0x2c, 0x20, 0x30, 0x36, 0x2f, 0x31, 0x36, 0x2f, 
     0x32, 0x30, 0x31, 0x32, 0x2e, 0x20, 0x46, 0x75, 0x62, 0x61, 0x72, 
     0x61, 0x62, 0x6c, 0x65, 0x20, 0x52, 0x75, 0x6c, 0x65, 0x73, 0x21 }; 

} 

नियंत्रण:

import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.AbstractAction; 

@SuppressWarnings("serial") 
public class MyControl { 
    private MyModel model; 
    private PlayAction playAction = new PlayAction(); 
    private PauseAction pauseAction = new PauseAction(); 
    private StopAction stopAction = new StopAction(); 
    private List<MyProgressMonitor> progMonitorList = new ArrayList<MyProgressMonitor>(); 

    public MyControl(MyModel model) { 
     this.model = model; 

     model.addPropertyChangeListener(new MyPropChangeListener()); 
    } 

    public void addProgressMonitor(MyProgressMonitor progMonitor) { 
     progMonitorList.add(progMonitor); 
    } 

    public void addView(MySetActions setActions) { 
     setActions.setPlayAction(playAction); 
     setActions.setPauseAction(pauseAction); 
     setActions.setStopAction(stopAction); 
    } 

    private class MyPropChangeListener implements PropertyChangeListener { 
     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
     if (MyState.class.getName().equals(pcEvt.getPropertyName())) { 
      MyState state = (MyState) pcEvt.getNewValue(); 

      if (state == MyState.PLAY) { 
       playAction.setEnabled(false); 
       pauseAction.setEnabled(true); 
       stopAction.setEnabled(true); 
      } else if (state == MyState.PAUSE) { 
       playAction.setEnabled(true); 
       pauseAction.setEnabled(false); 
       stopAction.setEnabled(true); 
      } else if (state == MyState.STOP) { 
       playAction.setEnabled(true); 
       pauseAction.setEnabled(false); 
       stopAction.setEnabled(false); 
      } 
     } 
     if (MyModel.PROGRESS.equals(pcEvt.getPropertyName())) { 
      for (MyProgressMonitor progMonitor : progMonitorList) { 
       int progress = (Integer) pcEvt.getNewValue(); 
       progMonitor.setProgress(progress); 
      }    
     } 
     } 
    } 

    private class PlayAction extends AbstractAction { 
     public PlayAction() { 
     super("Play"); 
     putValue(MNEMONIC_KEY, KeyEvent.VK_P); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
     model.play(); 
     } 
    } 

    private class StopAction extends AbstractAction { 
     public StopAction() { 
     super("Stop"); 
     putValue(MNEMONIC_KEY, KeyEvent.VK_S); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
     model.stop(); 
     } 
    } 
    private class PauseAction extends AbstractAction { 
     public PauseAction() { 
     super("Pause"); 
     putValue(MNEMONIC_KEY, KeyEvent.VK_A); 
     } 

     @Override 
     public void actionPerformed(ActionEvent e) { 
     model.pause(); 
     } 
    } 
} 

एक राज्य Enum:

public enum MyState { 
    PLAY, STOP, PAUSE 
} 

दृश्य इंटरफेस में से एक:

import javax.swing.Action; 

public interface MySetActions { 

    void setPlayAction(Action playAction); 
    void setPauseAction(Action pauseAction); 
    void setStopAction(Action stopAction); 
} 

एक अन्य दृश्य इंटरफ़ेस:

public interface MyProgressMonitor { 
    void setProgress(int progress); 
} 

मुख्य जीयूआई दृश्य:

import java.awt.BorderLayout; 
import java.awt.GridLayout; 

import javax.swing.Action; 
import javax.swing.BorderFactory; 
import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JPanel; 
import javax.swing.JProgressBar; 

public class MyView implements MySetActions, MyProgressMonitor { 
    private JButton playButton = new JButton(); 
    private JButton stopButton = new JButton(); 
    private JButton pauseButton = new JButton(); 
    private JPanel mainPanel = new JPanel(); 
    private JProgressBar progressBar = new JProgressBar(); 

    public MyView() { 
     progressBar.setBorderPainted(true); 

     JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0)); 
     btnPanel.add(playButton); 
     btnPanel.add(pauseButton); 
     btnPanel.add(stopButton); 

     mainPanel.setLayout(new BorderLayout(0, 5)); 
     mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15)); 
     mainPanel.add(btnPanel, BorderLayout.CENTER); 
     mainPanel.add(progressBar, BorderLayout.PAGE_END); 
    } 

    @Override 
    public void setPlayAction(Action playAction) { 
     playButton.setAction(playAction); 
    } 

    @Override 
    public void setStopAction(Action stopAction) { 
     stopButton.setAction(stopAction); 
    } 

    @Override 
    public void setPauseAction(Action pauseAction) { 
     pauseButton.setAction(pauseAction); 
    } 

    @Override 
    public void setProgress(int progress) { 
     progressBar.setValue(progress); 
    } 

    public JComponent getMainPanel() { 
     return mainPanel; 
    } 

} 

देखें का मेनू पट्टी भाग:

import java.awt.event.KeyEvent; 
import javax.swing.Action; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 

public class MyMenuBar implements MySetActions { 
    private JMenuItem playMenItem = new JMenuItem(); 
    private JMenuItem pauseMenuItem = new JMenuItem(); 
    private JMenuItem stopMenItem = new JMenuItem(); 
    private JMenuBar menuBar = new JMenuBar(); 

    public MyMenuBar() { 
     JMenu menu = new JMenu("Main Menu"); 
     menu.setMnemonic(KeyEvent.VK_M); 
     menu.add(playMenItem); 
     menu.add(pauseMenuItem); 
     menu.add(stopMenItem); 
     menuBar.add(menu); 
    } 

    public JMenuBar getMenuBar() { 
     return menuBar; 
    } 

    @Override 
    public void setPlayAction(Action playAction) { 
     playMenItem.setAction(playAction); 
    } 

    @Override 
    public void setStopAction(Action stopAction) { 
     stopMenItem.setAction(stopAction); 
    } 

    @Override 
    public void setPauseAction(Action pauseAction) { 
     pauseMenuItem.setAction(pauseAction); 
    } 

} 

और अंत में, मॉडल:

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.beans.PropertyChangeListener; 
import javax.swing.Timer; 
import javax.swing.event.SwingPropertyChangeSupport; 

public class MyModel { 
    public final static String PROGRESS = "progress"; 
    protected static final int MAX_PROGRESS = 100; 
    private MyState state = null; 
    private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
     this); 
    private Timer timer; 
    private int progress = 0; 

    public MyState getState() { 
     return state; 
    } 

    public void setState(MyState state) { 
     MyState oldValue = this.state; 
     MyState newValue = state; 
     this.state = newValue; 
     pcSupport.firePropertyChange(MyState.class.getName(), oldValue, newValue); 
    } 

    public int getProgress() { 
     return progress; 
    } 

    public void setProgress(int progress) { 
     Integer oldValue = this.progress; 
     Integer newValue = progress; 
     this.progress = newValue; 
     pcSupport.firePropertyChange(PROGRESS, oldValue, newValue); 
    } 

    public void play() { 
     MyState oldState = getState(); 
     setState(MyState.PLAY); 

     if (oldState == MyState.PAUSE) { 
     if (timer != null) { 
      timer.start(); 
      return; 
     } 
     } 
     int timerDelay = 50; 
     // simulate playing .... 
     timer = new Timer(timerDelay, new ActionListener() { 
     int timerProgress = 0; 

     @Override 
     public void actionPerformed(ActionEvent actEvt) { 
      timerProgress++; 
      setProgress(timerProgress); 
      if (timerProgress >= MAX_PROGRESS) { 
       setProgress(0); 
       MyModel.this.stop(); 
      } 
     } 
     }); 
     timer.start(); 
    } 

    public void pause() { 
     setState(MyState.PAUSE); 
     if (timer != null && timer.isRunning()) { 
     timer.stop(); 
     } 
    } 

    public void stop() { 
     setState(MyState.STOP); 
     setProgress(0); 
     if (timer != null && timer.isRunning()) { 
     timer.stop(); 
     } 
     timer = null; 
    } 

    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.addPropertyChangeListener(listener); 
    } 

    public void removePropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.removePropertyChangeListener(listener); 
    } 
} 

कृपया पूछें कि इनमें से कोई भी कम भ्रमित है या नहीं।

+0

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

+0

@ पीएमएमपी: शायद [यह उदाहरण] (http://stackoverflow.com/a/15729267/522444) (कृपया लिंक पर क्लिक करें) जो एक जेफाइलकोजर का उपयोग करता है, आपकी मदद कर सकता है। –