Как вернуть значения из ActionListener, который не находится во внутреннем классе - PullRequest
0 голосов
/ 26 декабря 2018

Я новичок в Java, а также в StackOverflow , поэтому, пожалуйста, извините, если я что-то не так делаю.Я исправлю это немедленно!

Мой вопрос: : Как я могу вернуть переменную из класса, который реализует ActionListener, в переменную другого класса?

Класс, который реализует ActionListener, не является внутренним классом.

Я добровольно исключил импорт.

Вот пример:

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

Как я могу вернуть File_B.java path переменную в File_A.java * path переменную?

Я пытался написать метод, который его возвращает, но этот метод не отображается в списке всех методов, поэтому его невозможно вызвать.И я пытался также расширить Pick_Something с Gui и сделать path защищенным, но у меня был StackOverflowError.

Кто-нибудь видит, что я делаю неправильно или у меня есть представление о том, как это сделать?

Ответы [ 3 ]

0 голосов
/ 26 декабря 2018

Я бы порекомендовал использовать обратный вызов, который вам предоставит Java-8 java.util.function, и на самом деле Consumer<String> будет отлично работать здесь.Создайте своего получателя в исходном классе, и пусть класс ActionListener вызовет его метод .accept(...), передавая информацию непосредственно из класса слушателя в графический интерфейс с низкой связью.Например, если у вашего графического интерфейса есть JTextField с именем filePathTxtField, который вы хотите заполнить выбранным путем файла пользователя, который был получен с помощью ActionListener, тогда потребитель может выглядеть так:

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);
    }
}   
0 голосов
/ 26 декабря 2018

Вот то, что я пробовал, и надеюсь, что это поможет.В этом примере класс слушателя возвращает выбранный путь к главному окну.

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.Observer и Observable.Основной класс 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);
        }
    }
}
0 голосов
/ 26 декабря 2018

У меня вопрос: как я могу вернуть переменную из класса, реализующего ActionListener, в переменную другого класса?

Вы не можете.

Беглый взгляд на JavaDocs для 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 для изменения его состояния (путь выбран).

Itтакже разъединяет код, так как PathPicker не имеет значения, как задан путь, только то, что он уведомляется, когда он есть.

Примечание о путях ...

File является абстрактным представлением файла или пути файловой системы.Он обладает множеством действительно интересных функций, которые упрощают и упрощают работу с файловой системой.

Многие API также используют ссылку File для выполнения своих операций.Вам следует избегать преобразования File в String, где это возможно, так как вы собираетесь лишить себя этой функциональности и усложнить свою жизнь в долгосрочной перспективе

...