【问题标题】:How do you create an ActionListener for multiple JMenuItems?如何为多个 JMenuItem 创建一个 ActionListener?
【发布时间】:2013-12-29 00:40:49
【问题描述】:

我在使用带有 actionListener 的匿名内部类时遇到了困难。有人可以向我解释我的代码有什么问题以及如何将匿名内部类与 actionListener 一起使用。我正在尝试在一个类中创建一个菜单栏,在另一个类中创建一个动作侦听器。当我尝试使用匿名内部类时遇到了一些困难。 java网站不清楚。能否请您向我解释一下并帮助我修复我的代码。

 public class Listener implements ActionListener {
        HangmanView hangmanView = new HangmanView();
        JFrame dialogFrame = new JFrame();
        ImageIcon logo = new ImageIcon("logo.png");

        public void listener1() {
            hangmanView.getMenuItem().addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {// right click key
                    JOptionPane.showMessageDialog(dialogFrame, "Developer: Joe"
                            , "Developer",
                            JOptionPane.INFORMATION_MESSAGE, logo);
                }// end actionPerformed method
            });
        }
    }

另一个类:

public class HangmanView {

    public JMenuItem getMenuItem() {
        JMenuItem menuItem = new JMenuItem("Developer", KeyEvent.VK_T);
        menuItem.addActionListener(new Listener());
        return menuItem;
    }

    public JMenuBar menuBar() {

        JMenuBar menuBar = new JMenuBar();
        JMenu menu = new JMenu("File");
        menuBar.add(menu);
        menu.add(getMenuItem());// return here
        return menuBar;
    }

【问题讨论】:

  • 为您的侦听器定义一个命名类而不是匿名内部类,并将其用作菜单项的操作侦听器。

标签: java swing actionlistener anonymous-class jmenuitem


【解决方案1】:

如果您尝试为不同的JMenuItems 实现侦听器,我会做的是创建一个自定义Action 类,您可以将其用于多个JMenuItems,因为JMenuItems 是何时使用Action 的好例子。

private class MyAction extends AbstractAction {

    String name;

    public MyAction(String name, Icon icon) {
        super(name, icon);
        this.name = name;
    }

    public MyAction(String name, Icon icon, String desc,
            Integer mnemonic, KeyStroke accelorator) {
        super(name, icon);
        putValue(Action.SHORT_DESCRIPTION, desc);
        putValue(Action.MNEMONIC_KEY, mnemonic);
        putValue(Action.ACCELERATOR_KEY, accelorator);
        this.name = name;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        switch (name) {
            case "menu1Action":
                // do something for menuItem1
                break;
            case "menu2Action":
                // do something for menuItem2
                break;
            case "menu3Action":
                // do something for menuItem3
                break;
        }
    }
}

将此类作为HangmanView 的内部类。然后,您可以为每个 JMenuItem 创建此自定义 Action 类的实例。这是一个例子

Action menu1Action = new MyAction(
 /* arg 1 */    "menu1Action", 
 /* arg 2 */    someIcon,
 /* arg 3 */    "Some Short description of the action",
 /* arg 4 */    new Integer(KeyEvent.VK_T),
 /* arg 5 */    KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK));
  • 第一个参数是操作的名称。此名称将是您将在菜单中看到的名称
  • 第二个参数是您将在名称旁边的菜单中看到的图标。
  • 第三个参数是菜单项动作的描述
  • 第四个参数是助记符(即 Alt + T)。
  • 第五个参数是加速器(即Ctrl + T)。

当您将Action 添加到JMenu 时,该Action 的标题将自动放置为您在JMenu 中看到的内容。因此,您需要做的就是将此自定义Action 添加到您的JMenu。您根本不必实际创建JMenuItemAction 将替代JMenuItem。只需将所有 MyAction 对象添加到 JMenu

menu.add(menu1Action);

我遗漏的是actionPerformed 中每个单独的switch case 的实现。 case 将是您在构造函数中命名的 action。因为我将Action命名为“menu1Action”,所以我应该在switch case中有对应的名称。在这种情况下,您可以执行您的 JOptionPane 或您希望在单击或通过键盘访问 JMenuItem 时执行的任何其他操作。

使用Action 的另一个好处是它可以用于多种用途。使用您创建的相同MyAction menu1Action,您可以将相同的Action 用于JToolBar。无需对上述menu1Action 进行任何更改,您就可以这样做:

JTooBar toolbar = new JToolBar();
toolbar.add(menu1Action);

现在在您的工具栏和菜单项中,您可以执行相同的操作。工具栏将仅显示图标而不显示名称。

这是一个例子。我所做的是创建三个不同的MyAction 对象。一种用于左对齐,一种用于中心对齐,一种用于右对齐。这些操作中的每一个都分别用于三个单独的组件、一个菜单项、一个收费栏和一个按钮

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ActionInterfaceDemo extends JFrame {
    static JPanel buttonPanel = new JPanel();
    static FlowLayout flowLayout = new FlowLayout();

    public ActionInterfaceDemo(){


        ImageIcon centerIcon = new ImageIcon(
                ActionInterfaceDemo.class.getResource("image/centeralignment.png"));
        ImageIcon rightIcon = new ImageIcon(
                ActionInterfaceDemo.class.getResource("image/rightalignment.png"));
        ImageIcon leftIcon = new ImageIcon(
                ActionInterfaceDemo.class.getResource("image/leftalignment.png"));

        Action leftAction = new MyAction("Left", leftIcon,
                "Left alignment for the buttons in the panel",
                new Integer(KeyEvent.VK_L),
                KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
        Action rightAction = new MyAction("Right", rightIcon,
                "Right alignment for the buttons in the panel",
                new Integer(KeyEvent.VK_R),
                KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK));
        Action centerAction = new MyAction("Center", centerIcon,
                "Center alignment for the buttons in the panel",
                new Integer(KeyEvent.VK_C),
                KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));

        JMenuBar menuBar = new JMenuBar();
        JMenu menuAlignment = new JMenu("Alignment");
        setJMenuBar(menuBar);
        menuBar.add(menuAlignment);

        menuAlignment.add(leftAction);
        menuAlignment.add(centerAction);
        menuAlignment.add(rightAction);

        JToolBar toolBar = new JToolBar("Alignment");
        toolBar.setBorder(BorderFactory.createLineBorder(Color.BLUE));
        toolBar.add(leftAction);
        toolBar.add(centerAction);
        toolBar.add(rightAction);

        buttonPanel.setLayout(flowLayout);
        JButton jbtLeft = new JButton(leftAction);
        JButton jbtCenter = new JButton(centerAction);
        JButton jbtRight = new JButton(rightAction);
        buttonPanel.add(jbtLeft);
        buttonPanel.add(jbtCenter);
        buttonPanel.add(jbtRight);

        add(toolBar, BorderLayout.EAST);
        add(buttonPanel, BorderLayout.CENTER);

        pack();
        setLocationRelativeTo(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                new ActionInterfaceDemo();
            }
        });

    }

    private class MyAction extends AbstractAction {

        String name;

        public MyAction(String name, Icon icon, String desc,
                Integer mnemonic, KeyStroke accelorator) {
            super(name, icon);
            putValue(Action.SHORT_DESCRIPTION, desc);
            putValue(Action.MNEMONIC_KEY, mnemonic);
            putValue(Action.ACCELERATOR_KEY, accelorator);
            this.name = name;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            switch (name) {
                case "Left":
                    flowLayout.setAlignment(FlowLayout.LEFT);
                    break;
                case "Right":
                    flowLayout.setAlignment(FlowLayout.RIGHT);
                    break;
                case "Center":
                    flowLayout.setAlignment(FlowLayout.CENTER);
                    break;
            }
            buttonPanel.revalidate();
        }
    }
}

您可以在菜单、工具栏或按钮中按“左”,它们将产生相同的结果,因为它们源自相同的Action

如果你想测试一下,这是我使用的图片

注意您不必使用这些 exact 构造函数中的任何一个。您可以使用不同的参数创建自己的。这只是我喜欢使用的自定义。

也见 How to use Action tutorial

【讨论】:

    【解决方案2】:

    Listener,通过其继承层次结构成为ActionListener

    public class Listener implements ActionListener {
    

    需要实现一个actionPerfomed(ActionEvent) 方法

    @Override
    public void actionPerformed(ActionEvent e) {
        // implement it         
    }
    

    但是,由于您似乎要添加匿名 ActionListener,所以不要让您的 Listener 类实现 ActionListener。删除那个位。

    【讨论】:

    • 我之前尝试删除该位,但在 HangmanView 类中,我在 menuItem.addActionListener(new Listener()); 上收到错误消息说:AbstractButton 类型中的方法 addActionListener(ActionListener) 不适用于参数 (Listener) 如果您有更好的方法让我在一个类中拥有多个动作侦听器并在另一个类中拥有一起工作的菜单项,请说。
    • @anon 您正在尝试在两个不同的位置添加侦听器。任选其一。
    • 当我从 HangmanView 类中删除动作监听器时,单击菜单项时不会出现对话框。如果您能向我解释这样做的最佳方式,那就太好了。对不起,我是一个困惑的初学者。
    【解决方案3】:

    您的面向对象编程无处不在。您在 OP 中的代码看起来应该是某种 GUI,不同的类以某种方式协同工作,但它只是在各处创建新对象。它不起作用的原因太多了。我建议您坚持做一些简单的事情,直到您更好地了解这一切是如何工作的。

    您在另一个问题中也得到了一个非常好的建议,它很像这个问题,但您并没有真正遵循它。你的代码做了一些完全不同的事情。

    这是一个非常基本的 GUI。您有一个将所有内容都作为字段的对象。一切都在一个地方。包含对象是侦听器,并根据事件源决定要做什么。您应该坚持这样的设计,直到您对 OOP 更加熟悉为止。

    public class HangmanView
    implements ActionListener {
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new HangmanView().setFrameVisible(true);
                }
            });
        }
    
        private JFrame theFrame = new JFrame("Main Window");
        private JPanel theContent = new JPanel();
    
        private JMenuBar theBar = new JMenuBar();
        private JMenu fileMenu = new JMenu("File");
        private JMenuItem exitMenuItem = new JMenuItem("Exit");
        private JMenuItem devMenuItem = new JMenuItem("Developer");
    
        public HangmanView() {
            assert SwingUtilities.isEventDispatchThread();
    
            exitMenuItem.addActionListener(this);
            devMenuItem.addActionListener(this);
    
            fileMenu.add(exitMenuItem);
            theBar.add(fileMenu);
            theBar.add(devMenuItem);
    
            theContent.setPreferredSize(new Dimension(500, 500));
    
            theFrame.setJMenuBar(theBar);
            theFrame.setContentPane(theContent);
            theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            theFrame.pack();
            theFrame.setLocationRelativeTo(null);
        }
    
        public void setFrameVisible(boolean vis) {
            theFrame.setVisible(vis);
        }
    
        @Override
        public void actionPerformed(ActionEvent ae) {
            if(ae.getSource() == devMenuItem) {
                showDevDiag();
            } else if(ae.getSource() == exitMenuItem) {
                systemExit();
            }
        }
    
        private void showDevDiag() {
            JOptionPane.showMessageDialog(
                theFrame,
                "Developer: Joe",
                "Developer",
                JOptionPane.INFORMATION_MESSAGE,
                null
            );
        }
    
        private void systemExit() {
            System.exit(0);
        }
    }
    

    【讨论】:

      【解决方案4】:

      如果我应该使用匿名类,那就应该这样做:

      public static void main(String args[]){
          /*bla bla bla...*/
          JButton button1=new JButton("button1");
          button1.addActionListener(new ActionListener() {
              @Override
              public void actionPerformed(ActionEvent ae){
                  /*bla bla bla...*/
              }
          };
      }
      

      另一方面,我总是这样做:

      public class Class implements Runnable,ActionListener
      {
          private static Map<Thread,ActionEvent> THREAD_ATTRIB
          =new HashMap<Thread,ActionEvent> (0);
      
          JButton button1=new JButton("button1");
          JButton button2=new JButton("button2");
          //constructor
          public Class(){
              this.button1.addActionListener(this);
              this.button2.addActionListener(this);
          }
      
          @Override
          public void actionPerformed(ActionEvent ae){
              Thread thread=new Thread(this);
              THREAD_ATTRIB.put(thread,ae);
              thread.start();
          }
      
          @Override
          public void run(){
              ActionEvent ae=THREAD_ATTRIB.get(Thread.currentThread());
              if(ae!=null){
                  Object source=ae.getSource();
                  if(source.equals(this.button1){
                      /*bla bla bla...*/
                  } else if(source.equals(this.button2){
                      /*bla bla bla...*/
                  }
              } else{
                  /*bla bla bla...*/
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多