2008-10-08 2 views
1

Полное заявление об отказе от ответственности: Я студент CS, и этот вопрос связан с недавно назначенной программой Java для объектно-ориентированного программирования. Хотя мы сделали некоторые вещи в консоли, это первый раз, когда мы работали с графическим интерфейсом и Swing или Awt. Нам был предоставлен некоторый код, который создал окно с некоторым текстом и кнопкой, которая поворачивалась в разные цвета для текста. Затем нас попросили изменить программу для создания переключателей для цветов вместо этого - это также предназначалось для того, чтобы дать нам возможность исследовать API. Я уже передал свое задание и получил разрешение от моего инструктора разместить здесь свой код.Включение действия кнопки/реализации кнопки

Каков наилучший способ реализации действий кнопок в Java? После того, как некоторые пустячный вокруг, я создал кнопки, как это:

class HelloComponent3 extends JComponent 
    implements MouseMotionListener, ActionListener 
{ 
    int messageX = 75, messageY= 175; 

    String theMessage; 
    String redString = "red", blueString = "blue", greenString = "green"; 
    String magentaString = "magenta", blackString = "black", resetString = "reset"; 

    JButton resetButton; 
    JRadioButton redButton, blueButton, greenButton, magentaButton, blackButton; 
    ButtonGroup colorButtons; 

    public HelloComponent3(String message) { 

    theMessage = message; 

    //intialize the reset button 
    resetButton = new JButton("Reset"); 
    resetButton.setActionCommand(resetString); 
    resetButton.addActionListener(this); 

    //intialize our radio buttons with actions and labels 
    redButton = new JRadioButton("Red"); 
    redButton.setActionCommand(redString); 
    ... 

И добавил действий слушателей ...

redButton.addActionListener(this); 
blueButton.addActionListener(this); 
... 

Заглушка уже созданы для метода actionPerformed, чтобы дать нам представление о том, как используйте его, но поскольку в шаблоне была только одна кнопка, было непонятно, как реализовать несколько кнопок. Я попытался включить String, но быстро понял, что, поскольку String не является примитивным типом, я не мог использовать его для оператора switch. Я мог бы импровизировать с цепочкой if-else, но вместо этого я пришел к этому. Это кажется далеким от элегантности, и должен быть лучший способ. Если есть, что это? Есть ли способ включить строку? Или выбрать действие более масштабируемым способом?

public void actionPerformed(ActionEvent e){ 

    if (e.getActionCommand().equals(resetString)) { 
     messageX = 75; messageY = 175; 
     setForeground(Color.black); 
     blackButton.setSelected(true); 
     repaint(); 
     return; 
    } 

    if (e.getActionCommand().equals(redString)) { 
     setForeground(Color.red); 
     repaint(); 
     return; 
    } 

    if (e.getActionCommand().equals(blueString)) { 
     setForeground(Color.blue); 
     repaint(); 
     return; 
    } 

    if (e.getActionCommand().equals(greenString)) { 
     setForeground(Color.green); 
     repaint(); 
     return; 
    } 

    if (e.getActionCommand().equals(magentaString)) { 
     setForeground(Color.magenta); 
     repaint(); 
     return; 
    } 

    if (e.getActionCommand().equals(blackString)) { 
     setForeground(Color.black); 
     repaint(); 
     return; 
    } 
} 

ответ

1

Вместо того, чтобы писать это:

resetButton.addActionListener(this); 

Вы также можете написать это:

resetButton.addActionListener(new ActionListener() { 
    public void actionPerformed(ActionEvent evt) { 
     resetButtonActionPerformed(evt); 
    } 
}); 

И вместо того, чтобы писать один большой actionPerformed() для всех действий, вы можете (и затем необходимо) написать следующее:

public void resetButtonActionPerformed(ActionEvent evt) { 
    messageX = 75; messageY = 175; 
    setForeground(Color.black); 
    blackButton.setSelected(true); 
    repaint(); 
} 

Я не знаю, является ли это самым элегантным решением, но по крайней мере у вас больше нет такой большой конструкции if.

+0

Как правильно обозначено плинтусом, это может быть несколько (много) за пределами вашего нынешнего уровня образования. Тем не менее, я уверен, что вы станете вашим преподавателем самым любимым учеником (дня), если вы сможете понять, что на самом деле происходит здесь ****. :-) – 2008-10-08 19:58:03

+0

Я думаю, что я понимаю концепцию здесь, но я так не знаком с тем, как все эти методы и классы связаны с тем, что это немного сложно. Я попробую и посмотрю, смогу ли я хотя бы заставить его работать. Но ... actionPerformed метод, который является аргументом addActionListener? Или из ActionListener? – 2008-10-10 03:56:06

0

Два альтернативного подход:

  1. Создайте новый класс, который реализует интерфейс действий и имеет поле Color и метод actionPerformed, который устанавливает цвет
  2. означает сохранение в HashMap из имен команд в Раскраси экземпляров и посмотреть название команды на карте
-1

Ergh. Не реализуйте массу несвязанных интерфейсов в одном мега-классе. Вместо этого используйте неявные внутренние классы. Они немного подробные, но это то, что вы хотите. Используйте один для каждого события, тогда вам не понадобится большая цепочка if-else. Я предлагаю хранить достаточно кода внутри внутреннего класса для декодирования событий и методов вызова, которые имеют смысл для целевых объектов. Кроме того, вы можете параметризовать свои внутренние классы. Вы, вероятно, обнаружите, что вам не нужно поддерживать ссылки на фактические виджеты.

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

Так, например:

addColorButton("Green" , Color.GREEN); 
    addColorButton("Red" , Color.RED ); 
    addColorButton("Yellow", Color.YELLOW); 
    addColorButton("Blue" , Color.BLUE ); 
    ... 

private void addColorButton(String label, Color color) { 
    JRadioButton button = new JRadioButton(label); 
    button.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent event) { 
      target.setForeground(color); 
      target.repaint(); 
     } 
    }); 
    colorGroup.add(button); 
    panel.add(button); 
} 
0

Один приличный подход объявить enum whose elements match your strings и включите valueOf (НТР) (связанный пример показывает, как сделать это с изрядным количеством безопасности).

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

0

Как уже было предложено, вы можете использовать анонимные внутренние классы для реализации интерфейса ActionListener. В качестве альтернативы, вы не должны использовать анонимные внутренние классы, но вы можете использовать простой вложенный класс вместо:

resetButton = new JButton(new ResetAction()); 
redButton = new JButton(new ColorAction("Red", Color.red)); 

, а затем ...

private class ResetAction extends AbstractAction { 
    public ResetAction() { 
     super("Reset"); 
    } 

    public void actionPerformed(ActionEvent e) { 
     messageX = 75; messageY = 175; 
     setForeground(Color.black); 
     blackButton.setSelected(true); 
     repaint(); 
    } 
} 

private class ResetAction extends AbstractAction { 
    private Color color; 

    public ColorAction(String title, Color color) { 
     super(title); 
     this.color = color; 
    } 

    public void actionPerformed(ActionEvent e) { 
     setForeground(color); 
     repaint(); 
    } 
} 

почему этот подход - или любой подход, включающий внутренние классы, лучше, чем реализация ActionListener во внешнем классе, см. «Шаблоны проектирования»:

«Благоприятный» состав объекта «над» наследованием класса ». (Gang of Four 1995: 20)

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