MVC-Pattern кнопки включения на событии в Java - PullRequest
2 голосов
/ 19 ноября 2009

Я сейчас начинаю с MVC-Pattern и хочу кое-что обдумать. Представьте себе следующий случай:

У меня есть представление (очевидно). В этом представлении пользователь может выбрать файл, а затем нажать кнопку «Загрузить». Как только эта кнопка загрузки нажата, все остальные компоненты в моем графическом интерфейсе должны быть включены, поскольку они установлены на «отключен», пока не загружен файл.

Что я делал до сих пор:

Я создал вид по следующей схеме:

public class GUI implements Observer {
  private JButton loadButton, showButton;
  private JComboBox nameBox;
  private Controller controller = new Controller();

  // Initialising Component and so on...
  loadButton.addActionListener(... // calls the loadFile()-Method

  public void update(Observable arg0, Object arg1) {
    // What to do here?

  }
}

И такой контроллер:

public class Controller extends Observable {
  public void loadFile() {
    // Load selected File
    notifyObservers(); // <--- What should they be notified about in order to enable their component?
  }
}

Так что моя проблема в том, что я не уверен, имеет ли смысл включать компоненты через контроллер. Или лучше проверить в представлении, загружен ли файл, а затем включить компоненты?

Ответы [ 5 ]

3 голосов
/ 19 ноября 2009

Вы не показываете свою модель, но, вероятно, она «знает», был ли файл успешно загружен.

Так что я бы просто сказал, что «модель изменилась».

Тогда представление отвечает за решение, что показать, какие кнопки включить или что-то еще. Так что это может иметь такую ​​логику, как

if ( model.isFileLoaded() ){
     enable buttons
} else {
      disable all buttons except the load
      if ( model.hadError() ) {
          display helpful message (and let user specify a different file)
      }
}

Таким образом, контроллеру не нужно знать, какие конкретные элементы в модели интересны для просмотра, и не нужно ничего знать о кнопках и состоянии просмотра в целом.

2 голосов
/ 19 ноября 2009

Способ, которым я мог бы это сделать, - отключить все изменения в модели. Некоторый наблюдаемый бин может содержать «файл», а ваш «уровень контроллера» будет состоять из слушателей бина, которые обновляют состояния кнопок на основе наличия или отсутствия значения свойства «файл».

Это разъединяет все, так как вы можете легко добавлять дополнительные кнопки, удалять кнопки и т. Д. Без изменения вашего кода. Если у вас есть другой способ установки или очистки свойства «file», вам не нужно копировать + вставлять весь код отключения / включения.

Таким образом, в приведенном выше примере loadFile () загрузит файл и установит его для bean-компонента модели. Это изменение значения вызовет PropertyChangeEvents для ваших слушателей, которые обновляют состояние кнопки.

С моей точки зрения: дополнительная заслуга в манипулировании действиями с помощью непосредственно setEnable () кнопок. Действия могут даже быть слушателем изменения бина и просто вызывать setEnabled () для себя. Но мне нравится связывать код контроллера с реальными компонентами колебания настолько, насколько я могу сойти с рук.

Если это сбивает с толку, я могу предоставить пример кода. - хорошо, код предоставлен ...

Итак, мой "чистый" способ - это действия, поддерживающие все кнопки ... возможно, даже с общим базовым классом:

public abstract class FileRequiredAction extends AbstractAction 
                                implements PropertyChangeListener {
    public FileRequiredAction( String name ) {
        super( name );
    }

    public void propertyChanged( PropertyChangeEvent event ) {
        if ("file".equals( event.getName())
            setEnabled( event.getNewValue() != null );
    }
}

Затем, предположив, что у вас есть какой-то правильный компонент модели с методом setFile (), который запускает нужные события, ваш код установки пользовательского интерфейса будет выглядеть примерно так:

Action a;
a = new FileRequiredAction( "Show" ) {
        public void actionPerformed( ActionEvent event ) {
            // Do the showing
        }
    };
myBean.addPropertyChangeListener( "file", a );
JButton showButton = new JButton( a );

...repeat for other actions that require "file".

Все, что нужно сделать кнопке «Загрузить», это вызвать myBean.setFile (someNonNullValue), и кнопки активируются самостоятельно. Бонус в том, что какое-то другое действие очищает значение, которое они снова отключили.

Для полного кода я пропустил некоторые вещи, такие как проверка того, что действие инициализирует свое включенное состояние в случае, если myBean.getFile () уже имеет значение, и т. Д.

Надеюсь, это прояснит ситуацию.

0 голосов
/ 19 ноября 2009

Один из подходов, который я могу придумать, не используя классы Observer, следующий:

</p> <p>public class GUI {<br> private JButton loadButton, showButton;<br> private JComboBox nameBox;<br> ... </p> <pre><code>loadButton.addActionListener(new Controller(GUI)); public void enableShow(boolean b) { // enable Show button if b is true } public void enableName(boolean b) { // display Name combo box if b is true }

}

открытый класс Controller реализует ActionListener {
частный графический интерфейс пользователя;

public Controller(GUI v) {  
    this.view = v;  
}  

public void actionPerformed(ActionEvent pActionEvt) {  
    boolean status = loadFile();  
    if (status) {  
        view.enableShow(true);  
        view.enableName(true);  
    }
}  

private boolean loadFile(String file) {
    // loads the specified file and return true if load is successful  
}  

}

Платформа Swing заботится о вызове метода actionPerformed в контроллере
когда пользователь нажимает кнопку загрузки.

Вы также можете поместить метод loadFile в отдельный класс, который
будет действовать в качестве модели.

Одним из преимуществ сегрегации контроллера является то, что вы можете
модульное тестирование контроллера независимо с использованием некоторой фиктивной среды.
Или вы можете создать класс GUI для реализации интерфейса и затем использовать
внедрение зависимости в модульное тестирование логики в классе Controller.

0 голосов
/ 19 ноября 2009

Я не буду слишком усложняться со всей этой архитектурой ... В данном случае, с моей точки зрения, ваша модель - это просто файл (и его содержимое). Ваш взгляд - ваш взгляд ;-), а контроллер - кнопка / actionListener. Просто сделай:

class MyViewClass extends SomeSwingComponent

{

  JButton loadButton;
  JButton disabledEnabledButton;

  //....

  void init()
  { 
    //...
    loadButton.addActionListener(new ActionListener()
    {
       public void actionPerformed(ActionEvent e)
       {
          loadFile();
       }
     });
     disabledEnabledButton.setEnabled(false);
     //...
   }

  //....


 private void loadFile()
 {
   //doFileLoadingStuff synchoniously
   disabledEnabledButton.setEnabled(true);
 }
//...

}

Только Если пользователь может что-то сделать во время загрузки файла, вам следует подумать о загрузке файла в наблюдаемом потоке.

0 голосов
/ 19 ноября 2009

Контроллер - это слой, который контролирует вид. Так что если у вас есть какие-то правила, такие как кнопки отключения, контроллер должен знать это.

В вашем графическом интерфейсе должен соблюдаться договор, в котором указывается способ отключения / включения кнопок.

И ваш контроллер должен вызывать этот метод в соответствии с вашими правилами. Ваш графический интерфейс должен отправлять события, а контроллер - манипулировать ими.

Если вы сделаете это, ваш графический интерфейс и контроллер будут модульными. Когда вам придется изменить структуру GUI (переключиться на легкий клиент, использовать другую библиотеку ...), ваш контроллер не изменится. И, конечно же, вам не нужно внедрять какие-либо правила, потому что их знает только контроллер.

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