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

发布于 2024-07-06 12:59:00 字数 2434 浏览 5 评论 0原文

完整免责声明:我是一名计算机科学学生,这个问题与最近分配的面向对象编程的 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;
    }
}

Full disclaimer: I'm a CS student, and this question is related to a recently assigned Java program for Object-Oriented Programming. Although we've done some console stuff, this is the first time we've worked with a GUI and Swing or Awt. We were given some code that created a window with some text and a button that rotated through different colors for the text. We were then asked to modify the program to create radio buttons for the colors instead—this was also intended to give us practice researching an API. I've already handed in my assignment and received permission from my instructor to post my code here.

What's the best way to implement button actions in Java? After some fiddling around, I created the buttons like this:

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);
    ...

And added action listeners...

redButton.addActionListener(this);
blueButton.addActionListener(this);
...

A stub was already created for the actionPerformed method to give us an idea on how to use it, but since there was only a single button in the template, it wasn't clear how to implement multiple buttons. I tried switching on a String, but quickly realized that, since a String isn't a primitive type, I couldn't use it for a switch statement. I could have improvised with an if-else chain, but this is what I came up with instead. It seems far from elegant, and there must be a better way. If there is, what is it? Is there a way to switch on a string? Or choose an action in a more scaleable fashion?

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;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

眉目亦如画i 2024-07-13 12:59:00

这样写:

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()至少你不再有那么大的 if 结构。

Instead of writing this:

resetButton.addActionListener(this);

You could also write this:

resetButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent evt) {
        resetButtonActionPerformed(evt);
    }
});

And instead of writing one big actionPerformed() for all actions, you can (and then have to) write this:

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

I don't know if this is the most elegant solution, but at least you no longer have that big if construct.

梦过后 2024-07-13 12:59:00

两种替代方法:

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

Two alternate approaches:

  1. Create a new class that implements the Action interface and has a Color field and an actionPerformed method that sets the color
  2. Mantain a HashMap from command names to Color instances and look up the command name in the map
莫言歌 2024-07-13 12:59:00

一种足够好的方法是声明一个 其元素与您的字符串匹配的枚举 并打开 valueOf (str)(链接的示例展示了如何以相当的安全性做到这一点)。

避免匿名内部类的原因可能是因为该类还没有该构造,尽管这可能是最好的解决方案。

One decent enough approach is to declare an enum whose elements match your strings and switch on valueOf(str) (the linked example shows how to do this with a fair amount of safety).

The reason to avoid anonymous inner classes is probably because the class hasn't had that construct (yet), even though that might be the best solution.

庆幸我还是我 2024-07-13 12:59:00

正如已经建议的,您可以使用匿名内部类来实现 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 更好class 请参阅“设计模式”:

“优先考虑‘对象组合’而不是‘类继承’。” (Gang of Four 1995:20)

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

As suggested already, you can use anonymous inner classes to implement the ActionListener interface. As an alternative, you don't have to use anonymous inner classes, but you can use a simple nested class instead:

resetButton = new JButton(new ResetAction());
redButton = new JButton(new ColorAction("Red", Color.red));

and then...

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();
    }
}

For why this approach - or any approach involving inner classes - is better than implementing ActionListener in the outer class see "Design Patterns":

"Favor 'object composition' over 'class inheritance'." (Gang of Four 1995:20)

Choosing between anonymous inner classes and these named inner classes is a largely a matter of style, but I think this version is easier to understand, and clearer when there are lots of actions.

回忆凄美了谁 2024-07-13 12:59:00

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

Ergh. Don't implement masses of unrelated interfaces in one mega class. Instead, use anoymous inner classes. They are a bit verbose, but are what you want. Use one for each event, then you wont need big if-else chain. I suggest keeping enough code within the inner class to decode the event and call methods that make sense to the target objects. Further, you can parameterise your inner classes. You will probably find you don't need to keep references to the actual widgets around.

In your example you seem to be using a JComponent as a JPanel. There's not much difference, but use JPanel for collecting a block of widgets. Further there is unlikely any need to subclass it, so don't.

So for instance:

   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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文