James P.
James P.

Reputation: 19617

Passing a value between components

I have a JDialog which calls an AsbtractAction which brings up a JFileChooser so the user can select a directory. These are all separate classes. What is the proper way of passing a value from the JFileChooser so I can display the path to the directory in the JDialog?

Edit: Updated the question.

Upvotes: 3

Views: 4250

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285403

I'm no pro at this, but I believe that there are two common ways that I've used of passing values from one object in another object (and there are probably more), by pushing the values from one to the other and by pulling the values from one to the other. By pushing I mean the obvious way of doing it where class one has a reference to class two and calls a method in class2 passing the value in. In your example, the AbstractAction has a reference to the GUI and calls a method in the GUI to set the JTextField, like so:

  public void actionPerformed(ActionEvent arg0) {
     String text = "Text from MyPushAction";
     guiPanel.setPushPathFieldText(text); 
  }

The other way is more complicated where the GUI has a listener registered to the action and pulls the information from the GUI when notified that a property has changed. This may not be the best example of when you'd use this, but it can be a useful way to decouple code. An example of this is a bit more complicated. Here's an example of both:

import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.swing.*;

public class FuSwing {
    private static void createAndShowUI() {
        GuiPanel guiPanel = new GuiPanel();

        JFrame frame = new JFrame("FuSwing");
        frame.getContentPane().add(guiPanel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                createAndShowUI();
            }
        });
    }
}

class GuiPanel extends JPanel {
    private MyPullAction myPullAction = new MyPullAction();
    private JTextField pushPathField = new JTextField(20);
    private JButton pushActionButton = new JButton(new MyPushAction(this));
    private JTextField pullPathField = new JTextField(20);
    private JButton pullActionButton = new JButton(myPullAction);

    public GuiPanel() {
        add(pushActionButton);
        add(pushPathField);
        add(Box.createHorizontalStrut(15));
        add(pullActionButton);
        add(pullPathField);

        myPullAction.addPropertyChangeListener(new PropertyChangeListener() {

            public void propertyChange(PropertyChangeEvent evt) {
                if (evt.getPropertyName().equals(MyPullAction.TEXT_PROPERTY)) {
                    pullPathField.setText(evt.getNewValue().toString());
                }
            }
        });
    }

    public void setPushPathFieldText(String text) {
        pushPathField.setText(text);
    }
}

class MyPushAction extends AbstractAction {
    private GuiPanel guiPanel;

    public MyPushAction(GuiPanel guiPanel) {
        super("Push Action");
        this.guiPanel = guiPanel;
    }

    public void actionPerformed(ActionEvent arg0) {
        String text = "Text from MyPushAction";
        guiPanel.setPushPathFieldText(text);
    }

}

class MyPullAction extends AbstractAction {
    public static final String TEXT_PROPERTY = "text";
    private String text = "";
    private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    public MyPullAction() {
        super("Pull Action");
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        pcs.addPropertyChangeListener(listener);
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        String oldText = this.text;
        this.text = text;
        PropertyChangeEvent evt = new PropertyChangeEvent(this, TEXT_PROPERTY, oldText, text);
        pcs.firePropertyChange(evt);
    }

    public void actionPerformed(ActionEvent e) {
        setText("Text from MyPullAction");
    }
}

Upvotes: 3

Manuel Salvadores
Manuel Salvadores

Reputation: 16525

This is an incomplete example but I guess can give you an idea of how to achieve what you need. The important bit is to reference the property where you want the selection back like YourDialog.this.selectedFile=file;

See below how to place it in the code:

   public class YourDialog extends JDialog implements ActionListener {
          protected File selectedFile=null;
          //Constructor
          public YourDialog(JFrame frame, boolean modal, String message) {
                //... create button and added to the panel
                someButton.addActionListener(new AbstractAction {
                    public void actionPerformed(ActionEvent e) {
                            final JFileChooser fc = new JFileChooser();
                            int returnVal = fc.showOpenDialog(YourDialog.this);
                            if (returnVal == JFileChooser.APPROVE_OPTION) {
                                File file = fc.getSelectedFile();

                                // HERE IS THE TRICK I GUESS !!
                                YourDialog.this.selectedFile=file;
                            }
                    }

                });
          }
    }

I hope it helps and sorry for not posting a full example.

Edit

In essence we are not passing any parameters to the AbstractAction. The fact is that the AbstractAction can access any non-private properties of the "caller" by accessing like YourDialog.this.somePropertyOrMethod. This is because the AbstractAction is an anonymous class of YourDialog class.

Upvotes: 3

Related Questions