1

完全免责声明:我是一名 CS 学生,这个问题与最近分配的面向对象编程的 Java 程序有关。尽管我们已经完成了一些控制台的工作,但这是我们第一次使用 GUI 和 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 方法创建了一个存根,让我们了解如何使用它,但是由于模板中只有一个按钮,因此不清楚如何实现多个按钮。我尝试打开一个字符串,但很快意识到,由于字符串不是原始类型,我不能将它用于 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;
    }
}
4

5 回答 5

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 构造。

于 2008-10-08T19:08:01.580 回答
0

两种替代方法:

  1. 创建一个实现 Action 接口并具有 Color 字段和设置颜色的 actionPerformed 方法的新类
  2. 维护从命令名称到 Color 实例的 HashMap 并在地图中查找命令名称
于 2008-10-08T19:13:02.913 回答
0

一种足够体面的方法是声明一个枚举,其元素与您的字符串匹配并打开 valueOf(str) (链接的示例显示了如何在相当安全的情况下执行此操作)。

避免匿名内部类的原因可能是因为该类(还)没有那个构造,即使这可能是最好的解决方案。

于 2008-10-08T19:19:39.483 回答
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 更好,请参阅“设计模式”:

“偏爱‘对象组合’而不是‘类继承’。” (四人帮 1995:20)

在匿名内部类和这些命名内部类之间进行选择在很大程度上是一种风格问题,但我认为这个版本更容易理解,并且在有很多动作时更清晰。

于 2008-10-09T23:38:08.773 回答
-1

呃。不要在一个大型类中实现大量不相关的接口。相反,使用匿名内部类。它们有点冗长,但正是你想要的。每个事件使用一个,那么您将不需要大的 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);
}
于 2008-10-08T19:18:18.690 回答