打开字符串/实现按钮操作

时间:2008-10-08 18:38:52

标签: java swing awt

完全免责声明:我是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方法创建了一个存根,以便让我们了解如何使用它,但由于模板中只有一个按钮,因此不清楚如何实现多个按钮。我尝试打开一个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 个答案:

答案 0 :(得分: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构造。

答案 1 :(得分:0)

两种替代方法:

  1. 创建一个实现Action接口的新类,它具有Color字段和设置颜色的actionPerformed方法
  2. 将HashMap从命令名称添加到Color实例并在地图中查找命令名称

答案 2 :(得分:0)

一种不错的方法是声明enum whose elements match your strings并启用valueOf(str)(链接的示例显示如何以相当大的安全性执行此操作)。

避免使用匿名内部类的原因可能是因为该类尚未拥有该构造(即使这可能是最佳解决方案)。

答案 3 :(得分: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)

在匿名内部类和这些命名内部类之间进行选择在很大程度上取决于样式,但我认为这个版本更易于理解,并且在有大量操作时更清晰。

答案 4 :(得分:-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);
}