简体   繁体   中英

Trying to add ActionListener to JButtons

I cannot figure out how to add Actionlisteners to the JButton s, any help would be much appreciated.

public class Translator extends JPanel implements MouseListener, ActionListener {       

    private JButton french = new JButton();
    private JButton german = new JButton();
    private JButton irish = new JButton();

    public Translator(){
        french = new JButton("French");
        german = new JButton("German");
        irish = new JButton("Irish");           
        setLayout(new GridLayout(2,1));         
        buttonPanel.setLayout(new GridLayout(1,3));
        buttonPanel.add(french);
        buttonPanel.add(german);
        buttonPanel.add(irish);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        // TODO Auto-generated method stub
    }
}

There are plenty of ways to add an ActionListener , to a given JComponent (that supports it's use). I have added some comments in the code snippets, to help explain them a bit better, and some links in the comments for future reference.

1.) If the class implements the ActionListener interface, ie the class itself contains the actionPerformed(...) method , then one can do it, in this manner:

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

public class Skeleton implements ActionListener {   

    private JFrame frame;
    private JPanel contentPane;
    private JButton button;

    private void displayGUI() {
        frame = new JFrame("Skeleton");
        /*
         * EXIT_ON_CLOSE is same as putting System.exit(0),
         * which in some sense, doesnot allows one's
         * application to terminate graciously.
         */ 
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        button = new JButton("This is a button.");
        /*
         * This is one way of attaching an ActionListener
         * to the JButton, but the main disadvantage of
         * this approach is, it breaks encapsulation,
         * as you can see the public method, actionPerformed(),
         * is lying free to be accessed by any code outside
         * the scope of the class
         */
        button.addActionListener(this);

        contentPane.add(button);

        frame.setContentPane(contentPane);        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);                                
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Skeleton().displayGUI();
            }
        };
        EventQueue.invokeLater(runnable);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(frame, "BINGO!",
            "Information: ", JOptionPane.INFORMATION_MESSAGE);
    }    
}

2.) If one doesn't wants to create unnecessary class files. Then this approach, which uses, EventHandler can be used:

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

public class Example1 { 

    private JFrame frame;
    private JPanel contentPane;
    private JButton button;

    private void displayGUI() {
        frame = new JFrame("Skeleton");
        /*
         * EXIT_ON_CLOSE is same as putting System.exit(0),
         * which in some sense, doesnot allows one's
         * application to terminate graciously.
         */ 
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        button = new JButton("This is a button.");
        /*
         * This is another way of attaching 
         * an ActionListener to the JButton,
         * the main advantage of this approach
         * is, that one does not have to create
         * a new class to handle events
         * More info regarding the use of this 
         * approach, can be found on this link : 
         * http://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html
         */
        button.addActionListener((ActionListener)
                EventHandler.create(ActionListener.class
                        , Example1.this, "buttonAction", ""));

        contentPane.add(button);

        frame.setContentPane(contentPane);        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);                                
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Example1().displayGUI();
            }
        };
        EventQueue.invokeLater(runnable);
    }

    public void buttonAction(ActionEvent e) {
        JOptionPane.showMessageDialog(frame, "BINGO!",
            "Information: ", JOptionPane.INFORMATION_MESSAGE);
    }    
}

3.) If one is more concern about the concept of Encapsulation , then this approach is beneficial:

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

public class Example2 { 

    private JFrame frame;
    private JPanel contentPane;
    private JButton button;

    private ActionListener buttonActions = 
                            new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            JOptionPane.showMessageDialog(frame, "BINGO!",
                "Information: ", JOptionPane.INFORMATION_MESSAGE);
        }
    };

    private void displayGUI() {
        frame = new JFrame("Skeleton");
        /*
         * EXIT_ON_CLOSE is same as putting System.exit(0),
         * which in some sense, doesnot allows one's
         * application to terminate graciously.
         */ 
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        button = new JButton("This is a button.");
        /*
         * This is another way of attaching 
         * an ActionListener to the JButton,
         * the main advantage of this approach
         * is, it adheres to encapsulation.
         */
        button.addActionListener(buttonActions);

        contentPane.add(button);

        frame.setContentPane(contentPane);        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);                                
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Example2().displayGUI();
            }
        };
        EventQueue.invokeLater(runnable);
    }    
}

4.) If one is more inclined towards creation of Anonymous Classes, then this approach can be used:

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

public class Example3 { 

    private JFrame frame;
    private JPanel contentPane;
    private JButton button;

    private void displayGUI() {
        frame = new JFrame("Skeleton");
        /*
         * EXIT_ON_CLOSE is same as putting System.exit(0),
         * which in some sense, doesnot allows one's
         * application to terminate graciously.
         */ 
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        button = new JButton("This is a button.");
        /* 
         * This is the fourth way of attaching  
         * an ActionListener to the JButton, 
         * the main advantage of this approach 
         * is, it adheres to encapsulation, the 
         * public method remains hidden
         * inside the Anonymous Class
         * More info can be found on this link : 
         * http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
         * The main disadvantage of this approach is
         * that it doesnot gives you the privilege
         * of separation of concerns, which can
         * be done using the fifth approach,
         * which is MVC - Pattern (Model-View-Controller)
         * and moreover, it creates a hell lot of classes, in 
         * your project, which can lead to extra overhead
         */
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JOptionPane.showMessageDialog(frame, "BINGO!",
                    "Information: ", JOptionPane.INFORMATION_MESSAGE);
            }
        });

        contentPane.add(button);

        frame.setContentPane(contentPane);        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);                                
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Example3().displayGUI();
            }
        };
        EventQueue.invokeLater(runnable);
    }    
}

EDIT:

5.) This approach, includes using Action instead of ActionListener . This is to be used for sharing same functionality among various JComponent s, which leads to code reusability

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

public class Example4 { 

    private JFrame frame;
    private JPanel contentPane;
    private JMenuItem showMenuItem;
    private JButton button;

    private Action myActions;

    /*
     * This approach is basically used, when
     * one wants to share the same functionality
     * of different JComponents among each other,
     * without writing redundant codes for each
     * one of those components. Here JMenuItem
     * and JButton are both using the same 
     * functionality, to perform the same task.
     * More info can be found on this link:
     * http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html
     */
    private class MyActions extends AbstractAction {
        public MyActions(String title, String desc) {
            super(title);
            putValue(SHORT_DESCRIPTION, desc);
        }

        @Override
        public void actionPerformed(ActionEvent ae) {
            JOptionPane.showMessageDialog(frame, "BINGO!",
                    "Information: ", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    private void displayGUI() {
        frame = new JFrame("Skeleton");
        /*
         * EXIT_ON_CLOSE is same as putting System.exit(0),
         * which in some sense, doesnot allows one's
         * application to terminate graciously.
         */ 
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        contentPane = new JPanel();
        button = new JButton("This is a button.");

        myActions = new MyActions("Show", "A small description");
        button.setAction(myActions);

        contentPane.add(button);

        frame.setJMenuBar(getJMenuBar());
        frame.setContentPane(contentPane);        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);                                
    }

    private JMenuBar getJMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        showMenuItem = new JMenuItem(myActions);
        fileMenu.add(showMenuItem);

        menuBar.add(fileMenu);

        return menuBar;
    }

    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                new Example4().displayGUI();
            }
        };
        EventQueue.invokeLater(runnable);
    }    
}
french.addActionListener(an_instance_of_the_class_where_actionPerformed_is);

which, as I can see after the edit, would be this

Also, see this Example and some tutorial text in this corner of the web

I think that the reference to the tutorial and the many examples is highly relevant.

button.addActionListener(<your_ActionListener_here>);

In your case, it'll be:

french.addActionListener(this);

If you want to use the same ActionListener for all the three buttons, you can use the getSource() function of ActionEvent e to detect which button was actually pressed.

If you are using Java8, you can try this.

JButton french = new JButton("French");
french.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent ae){
        System.out.println("Button french clicked!");
    }
});
french.addActionListener(button -> System.out.println("Button Click listener..."));
JFrame frame = new JFrame("Button Listener Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(french, BorderLayout.CENTER);
frame.setSize(250, 250);
frame.setVisible(true);

Obviously the answer is place this into your addActionListener method.

The addActionListener method takes as an argument an object that implements ActionListener interface, this interface force you to implements/place-in-your-code the actionPerformed method which is the one that is called, when an action is triggered to the component that is assigned.

So, placing this in your method, it will search inside the object you passed, in our case, the Translator object for an actionPerformed method and call it.

this.french.addActionListener(this);

Of course there is a lot of code missing in order to work.

I really liked @Sandeep answer take use of lambda expression. You can see a full example below.

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Translator extends JPanel implements ActionListener {       

    private JButton french = new JButton();
    private JButton german = new JButton();
    private JButton irish = new JButton();

    @SuppressWarnings("empty-statement")
    public Translator(){
        french = new JButton("French");
        german = new JButton("German");
        irish = new JButton("Irish");           
//        setLayout(new GridLayout(2,1));         
        this.setLayout(new GridLayout(1,3));
        this.add(french);
        this.add(german);
        this.add(irish);

        ActionListener ac = (ActionEvent ae) -> { System.out.println(((JButton) ae.getSource()).getText()); };
        this.french.addActionListener(ac);
        this.german.addActionListener(ac);
        this.irish.addActionListener(ac);
        this.irish.addActionListener(Translator.this);

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println(((JButton) e.getSource()).getText());
    }

    public static void main(String[] args) {
        JFrame jframe = new JFrame("StackOverflow");
        jframe.add(new Translator());
        jframe.pack();
        jframe.setLocationRelativeTo(null);
        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setVisible(true);
    }
}
JButton button = new JButton("Button");
button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
        //To-Do
        //Button clicked
        });

Hope this helps, it's relatively simple! You just need to add an ActionListener to your desired JButton

To give you a broader idea of how to implement it in a case-scenario where I would like to run a new GUI frame after pressing a button:

startNewFrame.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Starting new frame");
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    NewFrame newFrame = new NewFrame();
                    newFrame.setVisible(true);
                    dispose();//Disposes of current frame
                }
            });
        }
    });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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