Как работать с качелями с нескольких классов - PullRequest
5 голосов
/ 22 мая 2011

Я просто хочу узнать кое-что о качелях 1) Как использовать модель MVC в качелях? 2) Скажи, что у меня есть главное окно, и мне нужно сделать меню отдельным классом, все компоненты - отдельным классом, и это будет лучший способ его интеграции

Ответы [ 2 ]

9 голосов
/ 22 мая 2011

ОК, это называется ответом с перерасходом, извините за это, но вот небольшой пример, который я привел, который пытается использовать простой шаблон MVC, чтобы сделать тривиальную вещь: нажмите кнопку и измените текст в JTextField. Это излишне, потому что вы можете сделать то же самое всего за несколько строк кода, но это иллюстрирует некоторые MVC в отдельных файлах и то, как модель контролирует состояние. Пожалуйста, задавайте вопросы, если что-то не так!

Основной класс, который собирает все вместе и начинает:

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

Класс просмотра:

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

}

Контроль:

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

Модель использует объект PropertyChangeSupport, чтобы позволить другим объектам (в данном случае представлению) прослушивать изменения состояния. Таким образом, модель в действительности является нашей «наблюдаемой», а точка зрения - «наблюдателем»

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

}

Простое перечисление State для инкапсуляции понятия состояния:

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

edit: я вижу, что вы также упомянули меню, поэтому я добавил поддержку меню с добавлением этого класса и добавлением нескольких строк в классе SwingMcvTest. Обратите внимание, что из-за разделения кода было легко внести это изменение в графический интерфейс, поскольку все, что нужно сделать в меню, - это вызвать методы управления. Не нужно ничего знать о модели или представлении:

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

Боже, как много кода, чтобы сделать мелочь! Я назначаю себя и свой код для награды Rube Goldberg на стеке на этой неделе.

4 голосов
/ 22 мая 2011

Swing имеет встроенный механизм, который упрощает реализацию MVC. Он имеет рамки действий. Класс, отвечающий за представление здания, должен заботиться о создании экземпляров подклассов JComponent и размещении их на панелях. Каждый компонент, который должен реагировать на действия пользователя, должен иметь соответствующее действие (b.setAction(myAction)). Я обычно создаю пакет com.myapp.actions и помещаю туда все действия. Иногда я также создаю абстрактное действие, но оно зависит от приложения. Действия позволяют отделить логику от уровня представления. Думайте о действии как о точке входа в «Модель».

Типичное приложение имеет больше элементов управления, чем действий. Некоторые элементы управления используют одно и то же действие. Например, вы можете сохранить файл, набрав Ctrl-S, нажав пункт меню или кнопку панели инструментов, используя контекстное меню и т. Д. Но все эти элементы управления вызовут одно и то же действие SaveFileAction.

Относительно вашего второго вопроса есть 2 разных способа. Первый основан на наследовании. Есть люди, которые расширяют JFrame, когда им нужен фрейм, и реализуют весь макет в этот специальный класс.

Другой подход заключается в создании набора служебных методов, которые генерируют макет. Я лично предпочитаю этот. Я думаю, что наследование следует использовать, если вам действительно нужен подкласс чего-то, например, когда вы хотите переопределить один из методов суперкласса (например, paint())

Надеюсь, мое описание поможет. Удачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...