Search code examples
javaswingactionlistenerinner-classes

How to return values from an ActionListener which is not in inner class


I am new in Java and also in StackOverflow so, please excuse me if I do wrong something. I will correct it immediately!

My question is: How could I return a variable which is in a class that implements an ActionListener into another class's variable?

The class that implements the ActionListener is not an inner class.

I voluntary omitted imports.

Here an example:

File_A.java

public class Gui extends JFrame {
    private JButton myButton;
    private String path;
    some other properties...

    public Gui () {
        myButton = new JButton("Some Text");
        myButton.AddActionListener(new Pick_Something());
    }
}

File_B.java

public class Pick_Something implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        JFileChooser selectElement = new JFileChooser();
        String path;
        int status = selectElement.showOpenDialog(null);

        if (status == JFileChooser.APPROVE_OPTION)
            path = selectElement.getSelectedFile().getAbsolutePath();
        else
            path = null;
    }
}

How could I return File_B.java's path variable in File_A.java's path variable?

I tried to write a method who returns it but the method does not appear in the list of all methods so it is impossible to call. And I tried also to extends Pick_Something with Gui and make path protected but I had a StackOverflowError.

Anyone see what I do wrong or have an idea about how to do?


Solution

  • I would recommend using a call-back, something that Java-8's java.util.function supplies for you, and in fact a Consumer<String> would work perfectly here. Create your Consumer in the original class, and have the ActionListener class call its .accept(...) method, passing information directly from the listener class to the GUI with low coupling. For example if your Gui has a JTextField called filePathTxtField that you want filled with the user's file path of choice, one obtained by the ActionListener, then the consumer could look like so:

    Consumer<String> consumer = (String text) -> {
        filePathTxtField.setText(text);
    };
    

    This would be created in the Gui class, and then passed into the ActionListener class via a constructor parameter:

    // in the Gui class's constructor
    button.addActionListener(new PickSomething(consumer));  
    

    // the PickSomething class and its constructor
    class PickSomething implements ActionListener {
        private Consumer<String> consumer;
    
        public PickSomething(Consumer<String> consumer) {
            this.consumer = consumer;
        }
    

    Then the actionPerformed method could look like:

    @Override
    public void actionPerformed(ActionEvent e) {
        JFileChooser selectElement = new JFileChooser();
        String path;
    
        // get the path String and set it
        int status = selectElement.showOpenDialog(null);
    
        if (status == JFileChooser.APPROVE_OPTION) {
            path = selectElement.getSelectedFile().getAbsolutePath();
        } else {
            path = null;
        }
    
        // pass the path String into the Gui by calling the call-back method, passing it in
        consumer.accept(path);
    }
    

    The whole thing could look like:

    import java.util.function.Consumer;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    @SuppressWarnings("serial")
    public class Gui extends JPanel {
        private JTextField filePathTxtField = new JTextField(45);
        private int foo = 0;
    
        public Gui() {
            filePathTxtField.setFocusable(false);
            add(filePathTxtField);
    
            JButton button = new JButton("Get File Path");
            Consumer<String> consumer = (String text) -> {
                filePathTxtField.setText(text);
            };
            button.addActionListener(new PickSomething(consumer));
            add(button);
        }
    
        private static void createAndShowGui() {
            Gui mainPanel = new Gui();
    
            JFrame frame = new JFrame("Gui");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(() -> createAndShowGui());
        }
    }
    

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.function.Consumer;
    import javax.swing.JFileChooser;
    
    public class PickSomething implements ActionListener {
        private Consumer<String> consumer;
    
        public PickSomething(Consumer<String> consumer) {
            this.consumer = consumer;
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            JFileChooser selectElement = new JFileChooser();
            String path;
            int status = selectElement.showOpenDialog(null);
    
            if (status == JFileChooser.APPROVE_OPTION) {
                path = selectElement.getSelectedFile().getAbsolutePath();
            } else {
                path = null;
            }
            consumer.accept(path);
        }
    }