Включение строки/реализация действий кнопки

StackOverflow https://stackoverflow.com/questions/184216

  •  06-07-2019
  •  | 
  •  

Вопрос

Полный отказ от ответственности:Я студент 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 не является примитивным типом, я не могу использовать его для оператора переключения.Я мог бы импровизировать с цепочкой 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;
    }
}
Это было полезно?

Решение

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

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.

Другие советы

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

<Ол>
  • Создайте новый класс, который реализует интерфейс Action и имеет поле Color и метод actionPerformed, который устанавливает цвет
  • Создайте HashMap из имен команд в экземпляры Color и найдите имя команды на карте
  • Достаточно приличный подход - объявить перечисление, элементы которого соответствуют вашим строкам и включите valueOf (str) (связанный пример показывает, как сделать это с достаточной степенью безопасности).

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

    Как уже предлагалось, вы можете использовать анонимные внутренние классы для реализации интерфейса 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 во внешнем классе, см. в разделе «Шаблоны проектирования»:

    " Пользуйся 'композицией объекта' над 'наследованием класса'. " (Банда Четырех, 1995: 20).

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

    Эрг.Не реализуйте массу несвязанных между собой интерфейсов в одном мегаклассе.Вместо этого используйте анонимные внутренние классы.Они немного многословны, но это то, что вам нужно.Используйте по одному для каждого события, тогда вам не понадобится большая цепочка 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);
    }
    
    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top