Структура программирования Java Swing: должны ли слушатели быть источником почти всех компонентов Swing? - PullRequest
5 голосов
/ 19 августа 2010

Мой вопрос сводится к следующему: является ли это стандартной структурой в программировании на Swing, чтобы дать слушателям контроль над новыми компонентами (например, новым JPanel) для отображения и ввода, и дать слушателям этого нового компонента контроль над новыми компонентами для отображения и ввода и так до бесконечности? Или же Java должна вернуться к какому-то объединяющему классу, который связывает все компоненты Swing вместе в процедурном порядке?

В настоящее время в моем приложении, которое использует только один JFrame, в моих слушателях мой начальный объект JFrame передается в качестве параметра всем моим JPanels, чтобы их слушатели могли вызывать removeall (), чтобы очистить кадр для нового JPanel. Например, короткий код следующим образом

public class MainFrame {
  JFrame jfrm;
  public MainFrame() {
    jfrm = new JFrame("Main Frame");
    JPanel mainPanel = new MainPanel(jfrm);
  }
}

public class MainPanel extends JPanel {
  public MainPanel(final JFrame mainFrame) {
    JButton example = new JButton("Example");
    example.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent le) {
            mainFrame.removeall();
            JPanel 2ndPanel = new 2ndPanel(mainFrame);
            mainFrame.add(2ndPanel);
            mainFrame.validate();
        }
    });
  }
}

Это правильная структура - где слушатели генерируют новые панели, а не какой-то объединяющий класс? Но если это так, как компилятор Java может добраться до mainFrame.validate (), если существует бесконечная каскадность слушателей? Я процедурный программист старой школы, пытающийся программировать Swing-приложение на Java, и я считаю, что, возможно, я не понял основные концепции программирования на Swing. С нетерпением ждем любых полезных ответов, и заранее спасибо!

Ответы [ 4 ]

4 голосов
/ 19 августа 2010

Я бы так не поступил. Шаблон Observer используется в Swing для отправки уведомлений, обычно в результате действий пользователя.

Возьмите ваш пример: пользователь «нажимает» на кнопку, потому что он хочет новую панель в MainFrame. Но кнопка не знает, что делать с кликом. Все, что он может сделать, это уведомить прослушивателей событий , что оно было выбрано.

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

Что возвращает нас к основному вопросу: , кто хочет получить информацию, если нажата кнопка, и , кто должен принять меры. Это главный вопрос дизайна. Определенно не слушатель, который создает и добавляет панель в основной кадр. Это может быть роль основного фрейма для создания и добавления дополнительных панелей или роль третьего компонента, который отвечает за создание фрейма с дополнительными панелями.

Но листнер - плохое место для этого кода.

3 голосов
/ 19 августа 2010

Вместо того, чтобы разрушать и создавать панели, вы можете захотеть посмотреть, как их скрыть / показать.Есть менеджер макетов CardLayout, который может сделать это: http://journals.ecs.soton.ac.uk/java/tutorial/ui/layout/card.html

По сути, идея заключается в сборке и добавлении всех ваших панелей в начале вашей проги, а затем с помощью менеджера компоновки переключаться между представлениями.

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

1 голос
/ 19 августа 2010

Существует некоторая путаница из-за того, как вы организовали свой код. Как общее правило Java, не делайте подклассы там, где у вас нет причин. Редко имеет смысл подкласс JPanel или JFrame.

Также редко имеет смысл назначать компоненты полям в классе, который их создает. На самом деле, делайте меньше в конструкторах.

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

1 голос
/ 19 августа 2010

Прежде всего, вы не должны позволять слушателю манипулировать кадром напрямую, используйте вложенный JPanel или ContentPane.

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

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

Я считаю передачу JFrame в качестве аргумента несколько избыточной.Почему бы не создать слушатель извне конструктора?

 final JPanel mainPanel = new MainPanel();     
 JButton example = new JButton("Example");
 example.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent le) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               MainFrame.this.removeAll();
               MainFrame.this.add(mainPanel);
            }
         });;
    }
 });
 add(example);

Это не лучший пример, но я уверен, что вы пытаетесь сделать.

Суть в том, что вы должнысоздайте компоненты вне слушателя, а затем добавьте его с помощью слушателя.

...