简体   繁体   English

如何为多个JMenuItem创建ActionListener?

[英]How do you create an ActionListener for multiple JMenuItems?

I'm having difficulty using anonymous inner classes with actionListener. 我在将匿名内部类与actionListener一起使用时遇到困难。 Can someone explain to me what is wrong with my code and how to use anonymous inner classes with actionListener. 有人可以向我解释我的代码有什么问题以及如何在actionListener中使用匿名内部类。 I'm trying to make a menu bar in one class and the action listener in the other. 我试图在一个类中创建一个菜单栏,在另一个类中创建一个动作侦听器。 I ran into some difficulty when I tried using anonymous inner classes. 当我尝试使用匿名内部类时遇到了一些困难。 The java website wasn't clear. Java网站不清楚。 Can you please explain it to me and help me fix my code. 您能否向我解释一下,并帮助我修复代码。

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

another class: 另一类:

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

If you're trying to implement the listener for different JMenuItem s, what I would do instead is create a custom Action class that you can use for multiple JMenuItem s, as JMenuItem s are a good example of when to use an Action . 如果要为不同的JMenuItem实现侦听器,我将改为创建一个可用于多个JMenuItem的自定义Action类,因为JMenuItem是何时使用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;
        }
    }
}

Have this class as an inner class of HangmanView . 将此类作为HangmanView的内部类。 You can then create an instance of this custom Action class for each JMenuItem . 然后,您可以为每个JMenuItem创建此自定义Action类的实例。 Here's a example 这是一个例子

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));
  • The first argument is the name of the action. 第一个参数是操作的名称。 This name will be the name that you will see in the menu 该名称将是您将在菜单中看到的名称
  • The second argument is the icon that you will see in the menu next to the name. 第二个参数是名称旁边您将在菜单中看到的图标。
  • The third argument is the Description of the menu item action 第三个参数是菜单项操作的描述
  • The fourth argument is the Mnemonic (ie Alt + T ). 第四个参数是助记符(即Alt + T )。
  • The fifth argument is the Accelerator (ie Ctrl + T ). 第五个参数是Accelerator(即Ctrl + T )。

When you add an Action to a JMenu , the title of that Action will automatically get placed as what you see in the JMenu . 当您将Action添加到JMenu ,该Action的标题将自动按照您在JMenu看到的位置放置。 So all you need to do is add this custom Action to your JMenu . 因此,您需要做的就是将此自定义Action添加到JMenu You don't ever have to actually create a JMenuItem at all. 您根本不需要真正创建JMenuItem The Action will serve as the replacement for the JMenuItem . Action将替代JMenuItem Just add all your MyAction objects to the JMenu . 只需将所有MyAction对象添加到JMenu

menu.add(menu1Action);

What I have left out, is the implementation for each separate switch case in the actionPerformed . 我遗漏的是actionPerformed每个单独的switch case的实现。 The case will be what you name the action in the constructor. 这种case将是您在构造函数中为action命名的名称。 Because I named the Action "menu1Action", I should have the corresponding name in the the switch case. 因为我将Action命名为“ menu1Action”,所以在switch的情况下应该有相应的名称。 In that case, you can do your JOptionPane or what ever else you wish to perform when that JMenuItem is clicked or accessed by keyboard. 在这种情况下,您可以执行JOptionPane或通过键盘单击或访问该JMenuItem时希望执行的其他操作。

Another great benefit of using an Action is that it can serve multiple purposes. 使用Action另一个巨大好处是它可以用于多种目的。 With the same MyAction menu1Action you created, you can use the same Action for a JToolBar . 使用与您创建的相同的MyAction menu1Action ,可以对JToolBar使用相同的Action Without any alteration to the above menu1Action , you could just do this: 无需对上述menu1Action任何更改,您可以执行以下操作:

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

Now in your tool bar and in your menu item, you have the same action. 现在,在工具栏和菜单项中,您将执行相同的操作。 The tool bar will only show the icon and not the name. 工具栏将仅显示图标,而不显示名称。

Here is an example. 这是一个例子。 What I do is create three different MyAction objects. 我要做的是创建三个不同的MyAction对象。 One for left-alignment, one for center-alignment, and one for right-alignment. 一种用于左对齐,一种用于居中对齐,另一种用于右对齐。 Each of these actions is used three separate times for three separate components, a menu item, a toll bar and a button 对于三个单独的组件,菜单项,收费栏和按钮,每个操作都要分别使用三个不同的时间

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

在此处输入图片说明

You can press the "Left" in either the menu, the toolbar, or the button and they will produce the same result, as they are derived from the same Action . 您可以在菜单,工具栏或按钮中按“左”键,它们将产生相同的结果,因为它们是从同一Action派生的。

Here are the images I used if you want to test it out 这是我用来测试的图像

在此处输入图片说明在此处输入图片说明在此处输入图片说明

Note You don't have to use either of these exact constructors. 注意您不必使用这两个确切的构造函数。 You can create your own with different arguments. 您可以使用不同的参数创建自己的参数。 This is just a custom one I like to use. 这只是我喜欢使用的一种自定义。

Aslo See How to use Action tutorial 请参阅《 如何使用Action》教程

Listener , being an ActionListener through its inheritance hierarchy, Listener ,是通过其继承层次结构构成的ActionListener

public class Listener implements ActionListener {

needs to implement an actionPerfomed(ActionEvent) method 需要实现一个actionPerfomed(ActionEvent)方法

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

However, since you seem to be adding an anonymous ActionListener , just don't have your Listener class implement ActionListener . 但是,由于您似乎要添加一个匿名ActionListener ,所以不要让您的Listener类实现ActionListener Remove that bit. 删除该位。

Your object-oriented programming is all over the place. 面向对象的编程无处不在。 Your code in the OP looks like it's supposed to be some kind of GUI with different classes somehow working together but it's just creating new objects all over the place. 您在OP中的代码看起来应该是某种具有不同类的GUI,它们可以以某种方式协同工作,但它只是在各处创建新对象。 There are too many reasons it doesn't work. 有太多原因不起作用。 I'd suggest you stick to something simple until you have a better grasp on how all this works. 我建议您坚持一些简单的事情,直到您对所有这些如何工作有更好的了解。

You also got a very good suggestion in your other question that's a lot like this one but you haven't really followed it. 您在另一个问题中也提出了一个很好的建议,就像这个问题一样,但是您并未真正遵循它。 Your code does something completely different. 您的代码所做的事情完全不同。

Here is a very basic GUI. 这是一个非常基本的GUI。 You have one object that has everything as fields. 您有一个将所有内容都作为字段的对象。 Everything is in one place. 一切都在一个地方。 The containing object is the listener and decides what to do based on the event source. 包含的对象是侦听器,并根据事件源决定要做什么。 You should stick with a design like this until you are more comfortable with OOP. 您应该坚持这样的设计,直到您对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);
    }
}

if I should use anonymous class, that's what should be done: 如果我应该使用匿名类,那就应该这样做:

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...*/
        }
    };
}

On the other hand, I always do this: 另一方面,我总是这样做:

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...*/
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM