如何让多个按钮在 Swing 中单独工作?

How to make multiple buttons work individually in Swing?

我正在尝试开发一个应用程序,我决定学习 Swing 来创建 GUI。以前从来没学过这个,看起来很简单,但是我还没弄明白ActionListener.

我试图通过在控制台中生成一些调试文本来使按钮响应。

谁能看一看并指出显而易见的地方。

package GUI;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;  
public class MainMenu implements ActionListener{  
JFrame f;
JButton b,b1,b2,b3,b4;

MainMenu(){  
f=new JFrame();//creating instance of JFrame  
          
JButton b=new JButton("click1");//creating instance of JButton  
b.setBounds(130,50,100, 40);
JButton b2=new JButton("click2");//creating instance of JButton  
b2.setBounds(130,150,100, 40);
JButton b3=new JButton("click3");//creating instance of JButton  
b3.setBounds(130,250,100, 40);
JButton b4=new JButton("click4");//creating instance of JButton  
b4.setBounds(130,350,100, 40);
          
f.add(b);//adding button in JFrame  
f.add(b2);
f.add(b3);
f.add(b4);
f.setSize(400,500);//400 width and 500 height  
f.setLayout(null);//using no layout managers  
f.setVisible(true);//making the frame visible  
}  
  
public static void main(String[] args) {  
new MainMenu();  
    }

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource() == b)
        System.out.println("test 1");
     else if (e.getSource() == b2)
         System.out.println("test 2");
     else if
        (e.getSource() == b3)
         System.out.println("test 3");
     else if
        (e.getSource() == b4)
        System.out.println("test 4");
    
}  
}

提前致谢

在 Swing 中,“侦听器”基于一个称为“观察者模式”的简单概念。在对象注册的兴趣上,当他们插入的事情发生时,另一个对象会通知他们。

在你的例子中,当按钮被“激活”时。

但是,在解决这个问题之前,您需要解决另一个问题。

您正在隐藏变量...

public class MainMenu implements ActionListener {

    JFrame f;
    JButton b, b1, b2, b3, b4;

    MainMenu() {
        JButton b = new JButton("click1");//creating instance of JButton  
        JButton b2 = new JButton("click2");//creating instance of JButton  
        JButton b3 = new JButton("click3");//creating instance of JButton  
        JButton b4 = new JButton("click4");//creating instance of JButton  
    }
}

您已将 bb1b2b3b4 声明为 MainMenu 的属性,但在构造函数将它们重新声明为局部变量,其上下文仅在构造函数中可用。这意味着,如果任何其他方法试图引用这些属性,它们将发现它们是 null

现在我们已经发现了这个问题,我们可以纠正它,并添加神奇的酱料让您的代码正常工作...

b = new JButton("click1");//creating instance of JButton  
b2 = new JButton("click2");//creating instance of JButton  
b3 = new JButton("click3");//creating instance of JButton  
b4 = new JButton("click4");//creating instance of JButton  

b.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);

在这里,我们只是说,“按钮,当你被操作时告诉我”

示例...

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class MainMenu implements ActionListener {

    JFrame f;
    JButton b, b1, b2, b3, b4;

    MainMenu() {
        f = new JFrame();//creating instance of JFrame  

        b = new JButton("click1");//creating instance of JButton  
        b2 = new JButton("click2");//creating instance of JButton  
        b3 = new JButton("click3");//creating instance of JButton  
        b4 = new JButton("click4");//creating instance of JButton  

        b.addActionListener(this);
        b2.addActionListener(this);
        b3.addActionListener(this);
        b4.addActionListener(this);

        JPanel content = new JPanel(new GridBagLayout());
        content.setBorder(new EmptyBorder(10, 10, 10, 10));
        f.setContentPane(content);

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(10, 0, 10, 0);
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        f.add(b, gbc);
        f.add(b2, gbc);
        f.add(b3, gbc);
        f.add(b4, gbc);

        f.pack();
        f.setVisible(true);//making the frame visible  
    }

    public static void main(String[] args) {
        new MainMenu();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == b) {
            System.out.println("test 1");
        } else if (e.getSource() == b2) {
            System.out.println("test 2");
        } else if (e.getSource() == b3) {
            System.out.println("test 3");
        } else if (e.getSource() == b4) {
            System.out.println("test 4");
        }

    }
}

您还应确保花时间通读 How to Use Actions and Laying Out Components Within a Container,这将为您将来省去很多麻烦。

扩张...

像大多数事情一样,要使用 ActionListener

您开始使用的方法(而且还不错)的“问题”是 actionPerformed 方法是 public,因此任何人都可以调用它。这可能不是一个坏主意,但它“泄漏”了可能更好地在内部进行约束的实现细节。

另一个“问题”是所有按钮都使用相同的 ActionListener。一般来说,这不是一件“坏”事,但它会很快使您的代码变得非常复杂,难以理解和维护。

在解决这些问题之前,我将解决使用对象引用来确定触发了什么的问题(正如我们在上面所做的那样)。同样,这不是一件“坏”事,但它开始限制它的重用,因为你可能有一个按钮、工具栏按钮和菜单按钮都想做同样的事情,重新使用不是很好吗?使用尽可能多的功能?

“动作命令”

使 ActionListener 更易于重用的一种简单方法是利用 actionCommand 属性。这使您可以指定一个 String,它可用于标识给定的操作,但可能会被用户以多种不同方式触发。

默认情况下,JButtonactionCommand 设置为按钮文本,但您可以指定您的按钮以使其更容易。

所以,从...开始...

b = new JButton("click1");//creating instance of JButton

然后使用类似...

@Override
public void actionPerformed(ActionEvent e) {
    if (e.getActionCommand().equals("click1")) {
        System.out.println("test 1");
    } //...
}

确定何时触发操作。这样做的重点是解耦逻辑。此实现不再依赖(耦合到)b 的实例!甜!

匿名类

另一种方法可能会使用“匿名 类”(诡异)。这是一个巧妙的功能,它允许您创建一个 interface 的内联实例(有人会指出我使用的术语是错误的),例如...

b.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("test 1");
    }
});

现在,当调用 actionPerformed 方法时,您可以保证实际触发它的人!无需 actionCommand 或引用检查。

有关详细信息,请参阅 Anonymous Classes

还有很多其他方法可以使这项工作成功,但我想我可能已经吓到你一个问题了;)

当然,您不需要为所有按钮使用共享 actionListener。如果每个按钮都有一个,通常可以产生更清晰的代码。所以你可以这样做:

这只是使用一个lambda为每个按钮注册一个简单的任务。打印语句也可以替换为执行更复杂任务的方法。

b.addActionListener(ae->System.out.println("test 1"));
b2.addActionListener(ae->System.out.println("test 2"));
b3.addActionListener(ae->System.out.println("test 3"));
b4.addActionListener(ae->System.out.println("test 4"));     

然后有一个实现 ActionListener 的私有 class,它可以通过构造函数获取值。

private static class MyActionListener implements ActionListener {
    String v;
    MyActionListener(String v) {
        this.v = v;
    }
    public void actionPerformed(ActionEvent e) {
        System.out.println(v);
    }
}

前面的 lambda 示例如下所示。

b.addActionListener(new MyActionListener("test 1"));
b2.addActionListener(new MyActionListener("test 2"));
b3.addActionListener(new MyActionListener("test 3"));
b4.addActionListener(new MyActionListener("test 4"));

所以你有很多选择。