Java 打开字符串/执行按钮操作

Java 打开字符串/执行按钮操作,java,swing,awt,Java,Swing,Awt,完整免责声明:我是一名CS学生,这个问题与最近分配的面向对象编程Java程序有关。虽然我们已经做了一些控制台的工作,但这是我们第一次使用GUI和Swing或Awt。我们得到了一些代码,这些代码创建了一个包含一些文本的窗口和一个按钮,该按钮在文本的不同颜色之间旋转。然后我们被要求修改程序,为颜色创建单选按钮,这也是为了让我们练习研究API。我已经交了作业,并且得到了老师的许可,可以在这里发布代码 在Java中实现按钮操作的最佳方法是什么?在做了一些修改之后,我创建了如下按钮: class Hell

完整免责声明:我是一名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;
    }
}

而不是写这封信:

resetButton.addActionListener(this);
你也可以这样写:

resetButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        resetButtonActionPerformed(evt);
    }
});
public void resetButtonActionPerformed(ActionEvent evt) {
    messageX = 75; messageY = 175;
    setForeground(Color.black);
    blackButton.setSelected(true);
    repaint();
}
与为所有操作编写一个大actionPerformed()不同,您可以(并且必须)编写以下内容:

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

我不知道这是否是最优雅的解决方案,但至少你不再有那么大的if构造。

两种替代方法:

  • 创建一个实现Action接口的新类,该类具有一个颜色字段和一个设置颜色的actionPerformed方法
  • Mantain从命令名到颜色实例的哈希映射,并在映射中查找命令名

  • 嗯。不要在一个大型类中实现大量不相关的接口。相反,请使用异常的内部类。它们有点冗长,但正是你想要的。每个事件使用一个,那么你就不需要大的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);
    }
    

    一种足够体面的方法是声明一个and on 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)


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

    正如普林斯正确指出的那样,这可能超出了你当前的教育水平。然而,如果你能弄清楚这里发生了什么事,我相信你会成为你的导师(一天中)最喜欢的学生。:-)我想我理解这里的概念,但是我太不熟悉所有这些方法和类是如何相互关联的,这有点令人生畏。我会尝试一下,看看我是否至少能让它起作用。但是…actionPerformed是作为addActionListener参数的方法吗?或者ActionListener?是的,在一个大型类中实现所有不相关的接口。别把这当成你的秋千课。模型视图控制器。您的JComponent就是您的视图。控制器类将实现所有侦听器接口。