如何添加侦听多个按钮的动作侦听器
Posted
技术标签:
【中文标题】如何添加侦听多个按钮的动作侦听器【英文标题】:How to add action listener that listens to multiple buttons 【发布时间】:2011-08-21 15:08:59 【问题描述】:我正试图找出我对动作侦听器做错了什么。我正在关注多个教程,但当我尝试使用动作侦听器时,netbeans 和 eclipse 给了我错误。
下面是一个简单的程序,我试图让一个按钮在其中工作。
我做错了什么?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class calc extends JFrame implements ActionListener
public static void main(String[] args)
JFrame calcFrame = new JFrame();
calcFrame.setSize(100, 100);
calcFrame.setVisible(true);
JButton button1 = new JButton("1");
button1.addActionListener(this);
calcFrame.add(button1);
public void actionPerformed(ActionEvent e)
if(e.getSource() == button1)
动作监听器从未注册,因为if(e.getSource() == button1)
它看不到button1
,错误提示找不到符号。
【问题讨论】:
1) 类名应该是 EachWordUpperCase。 2)除非添加功能,否则不要扩展框架。 3) 如果扩展框架,您可能不需要在main(String[])
中实例化一个 4) 通常认为更好的做法是为每个需要的 GUI 元素添加一个动作侦听器,而不是使用一个 actionPerformed(ActionEvent)
方法一个巨大的 if/else 级联。 5) 如果您按照 (4) 中的建议进行操作,问题就会基本消失。
可以使用操作 - 许多 UI 元素以一致的方式执行相同操作(例如工具栏和按钮)打开的最佳选择。见docs.oracle.com/javase/tutorial/uiswing/misc/action.html
【参考方案1】:
静态方法中没有this
指针。 (我不相信这段代码甚至会编译。)
你不应该在像main()
这样的静态方法中做这些事情;在构造函数中进行设置。我没有编译或运行它来查看它是否真的有效,但试一试。
public class Calc extends JFrame implements ActionListener
private Button button1;
public Calc()
super();
this.setSize(100, 100);
this.setVisible(true);
this.button1 = new JButton("1");
this.button1.addActionListener(this);
this.add(button1);
public static void main(String[] args)
Calc calc = new Calc();
calc.setVisible(true);
public void actionPerformed(ActionEvent e)
if(e.getSource() == button1)
【讨论】:
完美,为我解决了问题,感谢您的帮助【参考方案2】:我很惊讶没有人提到使用动作命令。这是关联来源和听众的一种非常标准的方式。它真的很有用,如果;
您有多个事件源需要执行相同的操作(例如,如果您希望用户能够按文本字段上的 Enter 键而不是单击旁边的按钮) 您没有生成事件的组件的引用看;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class DontExtendJFrame implements ActionListener
private enum Actions
HELLO,
GOODBYE
public static void main(String[] args)
DontExtendJFrame instance = new DontExtendJFrame();
JFrame frame = new JFrame("Test");
frame.setLayout(new FlowLayout());
frame.setSize(200, 100);
JButton hello = new JButton("Hello");
hello.setActionCommand(Actions.HELLO.name());
hello.addActionListener(instance);
frame.add(hello);
JButton goodbye = new JButton("Goodbye");
goodbye.setActionCommand(Actions.GOODBYE.name());
goodbye.addActionListener(instance);
frame.add(goodbye);
frame.setVisible(true);
@Override
public void actionPerformed(ActionEvent evt)
if (evt.getActionCommand() == Actions.HELLO.name())
JOptionPane.showMessageDialog(null, "Hello");
else if (evt.getActionCommand() == Actions.GOODBYE.name())
JOptionPane.showMessageDialog(null, "Goodbye");
【讨论】:
DontExtendJFrameAndDontImplementXXListenerAtTopLevel :-) 为什么不扩展 JFrame?我一直被教导要这样做。 @Lucas 一般来说,人们应该更喜欢组合而不是继承。 @Lucas 请参阅en.wikipedia.org/wiki/Composition_over_inheritance、***.com/questions/49002/… 和my.safaribooksonline.com/book/programming/java/9780137150021/… 我建议购买和阅读最后一个链接中的Effective Java
这本书。【参考方案3】:
这是根据我的评论修改的源代码形式。请注意,应该在 EDT 上构建和更新 GUI,尽管我没有走那么远。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JFrame;
public class Calc
public static void main(String[] args)
JFrame calcFrame = new JFrame();
// usually a good idea.
calcFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final JButton button1 = new JButton("1");
button1.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent ae)
JOptionPane.showMessageDialog(
button1, "..is the loneliest number");
);
calcFrame.add(button1);
// don't do this..
// calcFrame.setSize(100, 100);
// important!
calcFrame.pack();
calcFrame.setVisible(true);
【讨论】:
我的天,谢谢,我开始认为所有的 Java 代码都是垃圾,结果是开发人员很垃圾。 这个 9 年的问题仍然有帮助 很高兴它确实有帮助,@SHikhaMittal! :) 顺便说一句,我是新手,我 4 个月前开始学习 java 需要帮助,这个堆栈溢出对初学者很不友好,虽然我一直在以错误的方式学习它,从现在开始,你能推荐任何可以建立我的基础的资源吗 @SHikhaMittal 我向语言本身的提供者推荐The Java Tutorials。这就是我学习 Java 的方式(好吧,这里还有 1000 多个问题和答案)。【参考方案4】:问题在于 button1 是一个局部变量。您只需更改添加 actionListener 的方式即可。
button.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent e)
//button is pressed
System.out.println("You clicked the button");
);
或者您将button1
设为全局变量。
【讨论】:
非常感谢您的帮助,这回答了我很多问题。【参考方案5】:您已被告知如何解决当前的问题,但我认为这里还有更重要的问题。
遵守约定。即使是一次性代码。这意味着类名的初始情况。
不要扩展你不需要的类。 JFrame
应该很少扩展。实际上,您并没有创建派生类的实例!!!
不要将一堆东西捆绑到一个类中。特别是,您通常一次最多只能子类型化一个主类或接口(不包括 Comparable
之类的东西)。
始终在 AWT 事件调度线程 (EDT) 上进行交互,包括构造、Swing/AWT GUI。它既丑陋又冗长,但这是适合您的 Java。
检查事件的来源有点小技巧。听众很小,所以你甚至不能声称蹩脚的表演借口。
所以:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Calc
public static void main(String[] args)
java.awt.EventQueue.invokeLater(new Runnable() public void run()
runEDT();
);
private static void runEDT()
assert java.awt.EventQueue.isDispatchThread();
JFrame frame = new JFrame();
frame.setSize(100, 100);
JButton button1 = new JButton("1");
button1.addActionListener(new ActionListener()
public void actionPerformed(ActionEvent event)
...
);
frame.add(button1);
frame.setVisible(true);
如果您需要从侦听器中的封闭方法访问任何变量,请将它们设为final
。
【讨论】:
【参考方案6】:这里有很好的答案,但让我来谈谈添加监听多个按钮的动作监听器这一更全局的观点。
有两种流行的方法。
使用通用动作监听器
您可以在 actionPerformed(ActionEvent e)
实现中获取操作的来源:
JButton button1, button2; //your button
@Override
public void actionPerformed(ActionEvent e)
JButton actionSource = (JButton) e.getSource();
if(actionSource.equals(button1))
// YOU BUTTON 1 CODE HERE
else if (actionSource.equals(button2))
// YOU BUTTON 2 CODE HERE
使用 ActionCommand
通过这种方法,您可以设置按钮的actionCommand
字段,稍后您可以使用switch
:
button1.setActionCommand("actionName1");
button2.setActionCommand("actionName2");
后来:
@Override
public void actionPerformed(ActionEvent e)
String actionCommand = ((JButton) e.getSource()).getActionCommand();
switch (actionCommand)
case "actionName1":
// YOU BUTTON 1 CODE HERE
break;
case "actionName2":
// YOU BUTTON 2 CODE HERE
break;
查看learn more about JFrame Buttons, Listeners and Fields。
【讨论】:
【参考方案7】:第一个问题是button1
是main
方法的局部变量,所以actionPerformed
方法无权访问它。
第二个问题是ActionListener
接口是由calc
类实现的,但是main
方法中没有创建这个类的实例。
通常的做法是创建calc
的实例并将button1
设为calc
类的字段。
【讨论】:
非常感谢您的帮助,这回答了我很多问题。【参考方案8】:您在 main 方法中声明了 button1,因此您无法在 actionPerform 中访问它。您应该在课堂上将其设为全局。
JButton button1;
public static void main(String[] args)
JFrame calcFrame = new JFrame();
calcFrame.setSize(100, 100);
calcFrame.setVisible(true);
button1 = new JButton("1");
button1.addActionListener(this);
calcFrame.add(button1);
public void actionPerformed(ActionEvent e)
if(e.getSource() == button1)
【讨论】:
非常感谢您的帮助,这回答了我很多问题。【参考方案9】:首先,使用 super() 和构造函数正确扩展 JFrame 然后将动作侦听器添加到框架并添加按钮。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Calc extends JFrame implements ActionListener
JButton button1 = new JButton("1");
JButton button2 = new JButton("2");
public Calc()
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(100, 100);
button1.addActionListener(this);
button2.addActionListener(this);
calcFrame.add(button1);
calcFrame.add(button2);
public void actionPerformed(ActionEvent e)
Object source = e.getSource();
if(source == button1)
\\button1 code here
else if(source == button2)
\\button2 code here
public static void main(String[] args)
JFrame calcFrame = new JFrame();
calcFrame.setVisible(true);
【讨论】:
否(除了您根本没有使用 Calc 的疏忽——如果您实际运行您的示例,您会注意到什么;-) a) 不要扩展 JFrame,而是使用它 b) 不要实现 xxListener,而是使用它【参考方案10】:我使用“e.getActionCommand().contains(CharSecuence s)”,因为我来自 MVC 上下文,并且 Button 是在 View 类中声明的,但 actionPerformed 调用发生在控制器中。
public View()
....
buttonPlus = new Button("+");
buttonMinus = new Button("-");
....
public void addController(ActionListener controller)
buttonPlus.addActionListener(controller);
buttonMinus.addActionListener(controller);
我的控制器类实现了 ActionListener,因此,在覆盖 actionPerformed 时:
public void actionPerformed(ActionEvent e)
if(e.getActionCommand().contains("+"))
//do some action on the model
else if (e.getActionCommand().contains("-"))
//do some other action on the model
我希望这个其他答案也有用。
【讨论】:
【参考方案11】:使用我的方法,您可以以“经典方式”编写按钮单击事件处理程序,就像您在 VB 或 MFC 中所做的那样;)
假设我们有一个包含 2 个按钮的框架窗口类:
class MainWindow
Jbutton searchButton;
Jbutton filterButton;
您可以使用我的“路由器”类将事件路由回您的 MainWindow 类:
class MainWindow
JButton searchButton;
Jbutton filterButton;
ButtonClickRouter buttonRouter = new ButtonClickRouter(this);
void initWindowContent()
// create your components here...
// setup button listeners
searchButton.addActionListener(buttonRouter);
filterButton.addActionListener(buttonRouter);
void on_searchButton()
// TODO your handler goes here...
void on_filterButton()
// TODO your handler goes here...
你喜欢吗? :)
如果你喜欢这种方式而讨厌 Java 的匿名子类方式,那么你和我一样老。 'addActionListener(new ActionListener ...)' 的问题在于它将所有按钮处理程序压缩到一个外部方法中,这使得程序看起来是有线的。 (如果您在一个窗口中有多个按钮)
最后,路由器类在下面。您可以将其复制到您的程序中,无需任何更新。
只有一件事要提一下:按钮字段和事件处理程序方法必须可以被这个路由器类访问!简单地说,如果你在程序的同一个包中复制这个路由器类,你的按钮字段和方法必须是包可访问的。否则,它们必须是公开的。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ButtonClickRouter implements ActionListener
private Object target;
ButtonClickRouter(Object target)
this.target = target;
@Override
public void actionPerformed(ActionEvent actionEvent)
// get source button
Object sourceButton = actionEvent.getSource();
// find the corresponding field of the button in the host class
Field fieldOfSourceButton = null;
for (Field field : target.getClass().getDeclaredFields())
try
if (field.get(target).equals(sourceButton))
fieldOfSourceButton = field;
break;
catch (IllegalAccessException e)
if (fieldOfSourceButton == null)
return;
// make the expected method name for the source button
// rule: suppose the button field is 'searchButton', then the method
// is expected to be 'void on_searchButton()'
String methodName = "on_" + fieldOfSourceButton.getName();
// find such a method
Method expectedHanderMethod = null;
for (Method method : target.getClass().getDeclaredMethods())
if (method.getName().equals(methodName))
expectedHanderMethod = method;
break;
if (expectedHanderMethod == null)
return;
// fire
try
expectedHanderMethod.invoke(target);
catch (IllegalAccessException | InvocationTargetException e)
我是Java初学者(不是编程),所以上面的代码可能有什么不合适的地方。请在使用前检查一下。
【讨论】:
以上是关于如何添加侦听多个按钮的动作侦听器的主要内容,如果未能解决你的问题,请参考以下文章