如何从不在内部类中的ActionListener返回值

时间:2018-12-25 23:11:24

标签: java swing actionlistener inner-classes

我是Java和 StackOverflow 中的新手,所以,如果我做错了什么,请原谅。我会立即纠正!

我的问题是:如何将实现ADDENDUM的类中的变量返回到另一个类的变量中?

实现ActionListener的类不是内部类。

我自愿省略进口。

这里有个例子:

File_A.java

ActionListener

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

如何在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; } } 的{​​{1}}变量中返回File_B.java的{​​{1}}变量?

我试图编写一个返回它的方法,但是该方法未出现在所有方法的列表中,因此无法调用。而且我还尝试将path扩展为File_A.java,并保护path,但是我有一个Pick_Something

有人看到我做错了,或者对如何做有想法吗?

3 个答案:

答案 0 :(得分:3)

我建议使用回调,这是Java-8的java.util.function为您提供的,实际上,Consumer<String>在这里可以很好地工作。在原始类中创建您的Consumer,并让ActionListener类调用其.accept(...)方法,以较低的耦合将信息直接从侦听器类传递到GUI。例如,如果您的Gui拥有一个名为filePathTxtField的JTextField,您希望用用户选择的文件路径(由ActionListener获得的路径)填充该JTextField,则使用者可能看起来像这样:

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

这将在Gui类中创建,然后通过构造函数参数传递到ActionListener类:

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

然后,actionPerformed方法可能类似于:

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

整个过程看起来像:

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

答案 1 :(得分:2)

  

我的问题是:如何将实现ActionListener的类中的变量返回到另一个类的变量中?

你不能。

快速浏览JavaDocs for ActionListener将向您显示该方法未返回值。我非常确定,即使这样做也将一文不值,因为您的代码唯一知道该方法已被触发的时间是实际被调用的时间。

解决方案?将“模型”传递给ActionListener实现...

首先定义一个简单的interface或合同...

public PathPicker {
    public void setPath(File path);
}

然后更新PickSomething以接受此interface ...的实例...

public class PickSomething implements ActionListener {
    private PathPicker picker;

    public PickSomething(PathPicker picker) {
        this.picker = picker;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        JFileChooser selectElement = new JFileChooser();
        int status = selectElement.showOpenDialog(null);

        if (status == JFileChooser.APPROVE_OPTION) {
            picker.setPath(selectElement.getSelectedFile());
        } else {
            picker.setPath(null);
        }
    }
}

现在,您所要做的就是实现PathPicker接口,在创建时将其引用传递给PickSomething,然后等待其调用setPath

这通常称为“委托”(并且ActionListener也是其中的一个示例),其中实际负责将“委托”到其他对象。从很简单的意义上讲,它也是“可观察性”的一个示例,其中PickSomething的一个实例可以PathPicker的观察者来观察其状态(选择了路径)。

它也使代码解耦,因为PathPicker并不关心路径的设置,仅在设置路径时通知它。

关于路径的说明...

File是文件系统文件或路径的抽象表示。它具有许多非常酷的功能,使使用文件系统变得更加轻松和简单。

许多API也引用了File来执行其操作。您应该尽可能避免将File转换为String,因为从长远来看,您将抢劫该功能并使生活更加困难

答案 2 :(得分:0)

这是我尝试过的方法,希望对您有所帮助。在此示例中,侦听器类将所选路径返回到主窗口。

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

public class ActionListenerTester {

    private String path;
    private JLabel status;

    public static void main(String [] args) {
        new ActionListenerTester().gui();
    }
    private void gui() {
        JFrame frame = new JFrame();
        frame.setTitle("An External Listener");
        JLabel title = new JLabel("Get My Paths:");
        JButton button = new JButton("Get Path");
        button.addActionListener(new MyActionListener(this));
        status = new JLabel("Click the button to get path...");
        Container pane = frame.getContentPane();
        pane.setLayout(new GridLayout(3, 1));
        pane.add(title);
        pane.add(button);
        pane.add(status);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setSize(500, 300);        
        frame.setVisible(true);
    }

    public void setPath(String path) {
        this.path = path;
        status.setText(path);
    }
}

class MyActionListener implements ActionListener {

    private ActionListenerTester gui;

    public MyActionListener(ActionListenerTester gui) {
        this.gui = gui;
    }

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

        path = path.isEmpty() ? "No path selected!" : path;
        gui.setPath(path);
    }
}



替代方式:

当它不是内部类时,这是从操作侦听器类返回值的另一种方法。到主要的GUI类。这使用java.util.ObserverObservable对象。 GUI主类是观察者,而动作侦听器类中的选定路径是可观察的。当可观察对象(路径)更新时,将向观察者(GUI主类)发送路径值。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Observer;
import java.util.Observable;

public class ActionListenerTester2
        implements Observer {

    private String path;
    private JLabel status;

    public static void main(String [] args) {
        new ActionListenerTester2().gui();
    }
    private void gui() {
        JFrame frame = new JFrame();
        frame.setTitle("An External Listener 2");
        JLabel title = new JLabel("Get My Paths:");
        JButton button = new JButton("Get Path");
        button.addActionListener(new MyActionListener(this));
        status = new JLabel("Click the button to get path...");
        Container pane = frame.getContentPane();
        pane.setLayout(new GridLayout(3, 1));
        pane.add(title);
        pane.add(button);
        pane.add(status);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setSize(500, 300);        
        frame.setVisible(true);
    }

    /*
     * Observer interface's overridden method.
     * This method runs when the Observable object notifies
     * its observer objects (in this case, ActionListenerTester2)
     * about the update to the observable.
     */
    @Override
    public void update(Observable o, Object arg) {
        path = (String) arg;
        status.setText(path);
    }
}

class MyActionListener implements ActionListener {

    private PathObservable observable;

    public MyActionListener(ActionListenerTester2 gui) {
        observable = new PathObservable();
        observable.addObserver(gui);
    }

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

        System.out.println("Path: " + path);
        path = path.isEmpty() ? "No path selected!" : path;
        observable.changeData(path);
    }

    /*
     * When the Observable object changes, the notifyObservers()
     * method informs all the Observer objects - in this example
     * the main gui class: ActionListenerTester2.
     */
    class PathObservable extends Observable {

        PathObservable() {   
            super();
        }

        void changeData(Object data) {
            // the two methods of Observable class
            setChanged(); 
            notifyObservers(data);
        }
    }
}