Включение строки / выполнение действий кнопки - PullRequest
1 голос
/ 08 октября 2008

Полный отказ от ответственности: я студент 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;
    }
}

Ответы [ 5 ]

1 голос
/ 08 октября 2008

Вместо написания этого:

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 голосов
/ 10 октября 2008

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

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

0 голосов
/ 08 октября 2008

Один достаточно приличный подход - объявить перечисление , элементы которого соответствуют вашим строкам , и включить valueOf (str) (связанный пример показывает, как это сделать с достаточной степенью безопасности).

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

0 голосов
/ 08 октября 2008

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 голосов
/ 08 октября 2008

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

  1. Создайте новый класс, который реализует интерфейс Action и имеет поле Color и метод actionPerformed, который устанавливает цвет
  2. Создайте HashMap из имен команд в экземпляры Color и найдите имя команды на карте
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...