2011-05-22 28 views
5

Solo quiero saber algo sobre el columpio 1) ¿Cómo usar el modelo MVC en columpio? 2) Supongo que tengo una ventana principal y necesito hacer el menú como clase separada, todos los componentes como clase separada y .que será el mejor método para integrarloCómo trabajar con columpios con múltiples clases

+1

Publique en su pregunta un programa de ejemplo y podemos ayudar a solucionarlo con usted. –

Respuesta

9

OK, esto se llama responder con overkill, lo siento mucho, pero he aquí un ejemplo rápido que he acelerado que trata de usar un patrón MVC simple para hacer algo trivial: presionar un botón y cambiar el texto en un JTextField. Es excesivo porque podría hacer lo mismo en unas pocas líneas de código, pero ilustra algunos MVC en archivos separados y cómo el modelo controla el estado. Por favor, haga preguntas si algo es confuso.

La clase principal que pone a todos juntos y hace que las cosas empezaron:

import javax.swing.*; 

public class SwingMvcTest { 
    private static void createAndShowUI() { 

     // create the model/view/control and connect them together 
     MvcModel model = new MvcModel(); 
     MvcView view = new MvcView(model); 
     MvcControl control = new MvcControl(model); 
     view.setGuiControl(control); 

     // EDIT: added menu capability 
     McvMenu menu = new McvMenu(control); 

     // create the GUI to display the view 
     JFrame frame = new JFrame("MVC"); 
     frame.getContentPane().add(view.getMainPanel()); // add view here 
     frame.setJMenuBar(menu.getMenuBar()); // edit: added menu capability 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    // call Swing code in a thread-safe manner per the tutorials 
    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowUI(); 
     } 
     }); 
    } 
} 

La clase de vista:

import java.awt.*; 
import java.awt.event.*; 
import java.beans.*; 
import javax.swing.*; 

public class MvcView { 
    private MvcControl control; 
    private JTextField stateField = new JTextField(10); 
    private JPanel mainPanel = new JPanel(); // holds the main GUI and its components 

    public MvcView(MvcModel model) { 
     // add a property change listener to the model to listen and 
     // respond to changes in the model's state 
     model.addPropertyChangeListener(new PropertyChangeListener() { 
     public void propertyChange(PropertyChangeEvent evt) { 
      // if the state change is the one we're interested in... 
      if (evt.getPropertyName().equals(MvcModel.STATE_PROP_NAME)) { 
       stateField.setText(evt.getNewValue().toString()); // show it in the GUI 
      } 
     } 
     }); 
     JButton startButton = new JButton("Start"); 
     startButton.addActionListener(new ActionListener() { 
     // all the buttons do is call methods of the control 
     public void actionPerformed(ActionEvent e) { 
      if (control != null) { 
       control.startButtonActionPerformed(e); // e.g., here 
      } 
     } 
     }); 
     JButton endButton = new JButton("End"); 
     endButton.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      if (control != null) { 
       control.endButtonActionPerformed(e); // e.g., and here 
      } 
     } 
     }); 

     // make our GUI pretty 
     int gap = 10; 
     JPanel buttonPanel = new JPanel(new GridLayout(1, 0, gap, 0)); 
     buttonPanel.add(startButton); 
     buttonPanel.add(endButton); 

     JPanel statePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); 
     statePanel.add(new JLabel("State:")); 
     statePanel.add(Box.createHorizontalStrut(gap)); 
     statePanel.add(stateField); 

     mainPanel.setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap)); 
     mainPanel.setLayout(new BorderLayout(gap, gap)); 
     mainPanel.add(buttonPanel, BorderLayout.CENTER); 
     mainPanel.add(statePanel, BorderLayout.PAGE_END); 
    } 

    // set the control for this view 
    public void setGuiControl(MvcControl control) { 
     this.control = control; 
    } 

    // get the main gui and its components for display 
    public JComponent getMainPanel() { 
     return mainPanel; 
    } 

} 

El control:

import java.awt.event.ActionEvent; 

public class MvcControl { 
    private MvcModel model; 

    public MvcControl(MvcModel model) { 
     this.model = model; 
    } 

    // all this simplistic control does is change the state of the model, that's it 
    public void startButtonActionPerformed(ActionEvent ae) { 
     model.setState(State.START); 
    } 

    public void endButtonActionPerformed(ActionEvent ae) { 
     model.setState(State.END); 
    } 
} 

El modelo utiliza un objeto PropertyChangeSupport para permitir que otros objetos (en esta situación, la Vista) escuchen los cambios de estado. Por lo que el modelo es, en efecto, nuestro "observable", mientras que la vista es el "observador"

import java.beans.*; 

public class MvcModel { 
    public static final String STATE_PROP_NAME = "State"; 
    private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this); 
    private State state = State.NO_STATE; 

    public void setState(State state) { 
     State oldState = this.state; 
     this.state = state; 
     // notify all listeners that the state property has changed 
     pcSupport.firePropertyChange(STATE_PROP_NAME, oldState, state); 
    } 

    public State getState() { 
     return state; 
    } 

    public String getStateText() { 
     return state.getText(); 
    } 

    // allow addition of listeners or observers 
    public void addPropertyChangeListener(PropertyChangeListener listener) { 
     pcSupport.addPropertyChangeListener(listener); 
    } 

} 

Una simple enumeración, Estado, para encapsular el concepto de estado:

public enum State { 
    NO_STATE("No State"), START("Start"), END("End"); 
    private String text; 

    private State(String text) { 
     this.text = text; 
    } 

    @Override 
    public String toString() { 
     return text; 
    } 

    public String getText() { 
     return text; 
    } 
} 

edición: Veo que mencioné el menú también, así que agregué el soporte de menú con la adición de esta clase y la adición de varias líneas en la clase SwingMcvTest. Tenga en cuenta que debido a la separación del código, fue trivial hacer este cambio en la GUI ya que todo lo que el menú necesita hacer es llamar a los métodos de control.Se necesita saber nada del modelo o de la vista:

import java.awt.event.ActionEvent; 
import javax.swing.*; 

public class McvMenu { 
    private JMenuBar menuBar = new JMenuBar(); 
    private MvcControl control; 

    @SuppressWarnings("serial") 
    public McvMenu(MvcControl cntrl) { 
     this.control = cntrl; 

     JMenu menu = new JMenu("Change State"); 
     menu.add(new JMenuItem(new AbstractAction("Start") { 
     public void actionPerformed(ActionEvent ae) { 
      if (control != null) { 
       control.startButtonActionPerformed(ae); 
      } 
     } 
     })); 
     menu.add(new JMenuItem(new AbstractAction("End") { 
     public void actionPerformed(ActionEvent ae) { 
      if (control != null) { 
       control.endButtonActionPerformed(ae); 
      } 
     } 
     })); 

     menuBar.add(menu); 
    } 

    public JMenuBar getMenuBar() { 
     return menuBar; 
    } 
} 

Dios, que es un montón de código para hacer un poco trivial de Chit! Me nomino a mí mismo y a mi código para el premio Rube Goldberg de stackoverflow de esta semana.

+0

@MByD: ¡¡¡gracias !! :) –

+0

Inspirando (como siempre) :) (corrigió un error tipográfico) – MByD

+0

No Rube Goldberg; tal vez [Karl Weick] (http://en.wikipedia.org/wiki/Loose_coupling) para acoplamiento flojo. – trashgod

4

Swing tiene un mecanismo de compilación que simplifica la implementación de MVC . Tiene marco de Acciones. La clase responsable de la creación de vistas debe preocuparse por la creación de instancias de las subclases JComponent y colocarlas en los paneles. Cada componente que debería reaccionar en la actividad del usuario debería tener la Acción correspondiente (b.setAction(myAction)). Normalmente creo el paquete com.myapp.actions y pongo todas las acciones allí. A veces también creo acción abstracta, pero es específica de la aplicación. Las acciones le permiten separar la lógica de la capa de presentación. Piense en la acción como un punto de entrada para "Modelo".

La aplicación típica tiene más controles que acciones. Algunos controles reutilizan la misma acción. Por ejemplo, puede guardar el archivo presionando Ctrl-S, haciendo clic en el elemento del menú o en el botón de la barra de herramientas, usando el menú contextual, etc. Pero todos estos controles invocarán la misma acción SaveFileAction.

En relación con su segunda pregunta, hay 2 formas diferentes. Primero se basa en la herencia. Hay personas que extienden JFrame cuando necesitan marco e implementan todo el diseño en esta clase especial.

Otro enfoque es crear un conjunto de métodos de utilidad que generen el diseño. Yo personalmente prefiero este. Creo que se debe usar la herencia si realmente necesita una subclase de algo, por ejemplo, cuando desea anular uno de los métodos de clase superior (por ejemplo, paint())

Espero que mi descripción ayude. Buena suerte.

Cuestiones relacionadas