1

I have two JFrame (JFrame1 and JFrame2) with two JTextField1 and JTextField2. My question is when I write "Hello world " on JTextField2 from Jframe2 and then click on OK button, I see "Hello world " on JTextField1 on Jframe1 class.

How can I do this? I'm sorry if this is a newbie question but I'm learning..

Here is my code:

JFrame2:

private JFrame1 jf1;
private void btn2ActionPerformed(java.awt.event.ActionEvent evt) {                                     
    jf1.setjTextField1(this.jTextField2);
} 
Arash m
  • 99
  • 2
  • 12
  • Do you need JFrame1's textfield text to show on JFrame2's textfield as well? Meaning that, do you need both JFrame to be able to see each other? – user3437460 Jun 20 '15 at 20:17
  • can you post some more code of JFrame1 and JFrame2 – Madhan Jun 20 '15 at 20:38
  • Start by defining a interface which describes the functionality you want to expose (setText for example). Have your classes implement this interface. Pass a reference of the class (implementing the interface) to other, so when the ok button is triggered, you can pass the String to the other class via the interface – MadProgrammer Jun 20 '15 at 21:41
  • See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/q/9554636/418556) – Andrew Thompson Jun 21 '15 at 06:12

3 Answers3

2

What you are doing there is actually sending the reference to the actual JTextField from one frame to the other one.

That's probably not a good idea cause both frames would be end up referencing the same visual component.

What you probably want is to keep all visual components separate, but make the text of the second text field equal to the text in the first one.

Something like this:

private void btn2ActionPerformed(java.awt.event.ActionEvent evt) {                                     
    jf1.getjTextField1().setText(this.jTextField2.getText());
} 
eugenioy
  • 11,825
  • 28
  • 35
  • TNk for your fast reply. I write it but it dose not work for me. I don't know why. this is what I wrote: private void btn2ActionPerformed(java.awt.event.ActionEvent evt) { jf1 = new JFrame1(); jf1.getjTextField1().setText(this.jTextField2.getText()); } – Arash m Jun 20 '15 at 20:27
  • Actually it set jTextField1 truly but I can not see it's text on GUI. – Arash m Jun 20 '15 at 20:35
  • The problem is that you are doing "jf1 = new JFrame1();" inside the event. What you probably need is to already have the two frames already created in a window and have "jf1" referencing the first frame. Create the two frames when initializing the window. – eugenioy Jun 20 '15 at 20:39
  • your right. so, where i have to write "jf1 = new JFrame1();"? – Arash m Jun 20 '15 at 20:44
  • Sorry I did not do yet. – Arash m Jun 20 '15 at 21:14
  • Personally, I would avoid exposing components as public, as this encourages mis/unintended use – MadProgrammer Jun 20 '15 at 21:37
  • Yes. Finally I change Jframe2's variables to public. – Arash m Jun 21 '15 at 11:28
1

This is a complete working example I just coded out:

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

class FrameRunner
{
    public static void main(String[] args){
        MyFrame f1 = new MyFrame("Frame 1");
        MyFrame f2 = new MyFrame("Frame 2");

        f1.addRef(f2);
        f2.addRef(f1);                  
    }       
}

class MyFrame extends JFrame{

    JTextField txt = new JTextField(8);
    JButton btn = new JButton("Send");
    MyFrame f = null;   

    public MyFrame(String title){
        super(title);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLayout(new FlowLayout());
        setPreferredSize(new Dimension(400, 300));
        setVisible(true);
        add(btn);
        add(txt);
        pack();
        setLocationRelativeTo(null);
        init();         
    }

    public void addRef(MyFrame f){
        this.f = f; 
    }

    public void init(){
        btn.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e){
                f.update(txt.getText());
            }
        });     
    }

    public void update(String str){
        txt.setText(str);
    }   
}

In order to make the code short and easier for you to understand. Many of the things I did not following the conventions and I did not modularize the codes. But this should give you a very good idea of how you can pass in the reference of another JFrame.

This code shows an example of how Frame1 has a reference on Frame2. Yet Frame2 also has a reference on Frame1.

Whatever things you type in JFrame1 can be send to JFrame2's textfield. Same for the other way round.

user3437460
  • 17,253
  • 15
  • 58
  • 106
  • @Arashm You are welcome ;) Just make sure you don't accept someone else's answer, else my `tick` will be removed. ;p – user3437460 Jun 20 '15 at 20:50
  • @arashm Unless another answer presents a better solution of course ;) – MadProgrammer Jun 20 '15 at 21:33
  • So, problems: extending from JFrame, not really recommended; not initialising the UI from with the EDT, will be waiting for more problems from the op on that later; exposing an entire class to another, where the functionality of the class isn't required to complete the task, the frames don't need to know about each other in the full, as this exposes your object to mis/unintended use by the other. An interface which defend the functionality which could be performed would be a better solution. While it might work, it's a bunch of bad practices that new developers should learn to avoid – MadProgrammer Jun 20 '15 at 21:36
  • eugenioy's answer work truly. for now my question is where i have to write "jf1 = new JFrame1();"? – Arash m Jun 20 '15 at 21:47
  • @MadProgrammer I omitted a number of things in the code. In fact normally I don't extends from JFrame. most of the time I extends from JPanel and add it with a JFrame. I supposed OP should be able to deduce from the code how to pass the reference of specific components instead of the entire JFrame. Maybe you can post your solution as well? :) – user3437460 Jun 21 '15 at 09:33
1

You could use an Observer Pattern or Producer/Consumer Pattern to solve the problem.

The basic idea is, you have something that generates a value and something that either wants to be notified or consume the generated value.

One of the other prinicples you should take the time to learn is also Code to interface (not implementation). This sounds stranger then it is, but the the idea is to reduce the unnecessary exposure of your objects (to unintended/controlled modifications) and decouple your code, so you can change the underlying implementation without affecting any other code which relies on it

Given the nature of your problem, an observer pattern might be more suitable. Most of Swing's listener's are based on the same principle.

We start by defining the contract that the "generator" will use to provide notification of changes...

public interface TextGeneratorObserver {

    public void textGenerated(String text);
}

Pretty simple. This means we can safely provide an instance of any object that implements this interface to the generator and know that it won't do anything to our object, because the only thing it knows about is the textGenerated method.

Next, we need something that generates the output we are waiting for...

public class GeneratorPane extends JPanel {

    private TextGeneratorObserver observer;
    private JTextField field;
    private JButton button;

    public GeneratorPane(TextGeneratorObserver observer) {
        this.observer = observer;

        field = new JTextField(10);
        button = new JButton("OK");

        ActionListener listener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                observer.textGenerated(field.getText());
            }
        };

        button.addActionListener(listener);
        field.addActionListener(listener);

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = GridBagConstraints.REMAINDER;
        gbc.insets = new Insets(2, 2, 2, 2);

        add(field, gbc);
        add(button, gbc);
    }

}

This is just a simple JPanel, but it requires you to pass a instance of TextGeneratorObserver to it. When the button (or field) triggers the ActionListener, the ActionListener calls the textGenerated to notify the observer that the text has been generated or changed

Now, we need someone to observer it...

public class ObserverPanel extends JPanel implements TextGeneratorObserver {

    private JLabel label;

    public ObserverPanel() {
        label = new JLabel("...");
        add(label);
    }

    @Override
    public void textGenerated(String text) {
        label.setText(text);
    }

}

This is a simple JPanel which implements the TextGeneratorObserver interface and updates it's JLabel with the new text

Then, we just need to plumb it together

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                ObserverPanel op = new ObserverPanel();
                op.setBorder(new CompoundBorder(new LineBorder(Color.RED), new EmptyBorder(10, 10, 10, 10)));
                GeneratorPane pp = new GeneratorPane(op);
                pp.setBorder(new CompoundBorder(new LineBorder(Color.GREEN), new EmptyBorder(10, 10, 10, 10)));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridLayout(2, 1));
                frame.add(pp);
                frame.add(op);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

Observer

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • I like your solution and I believe many will benefit from it. But I have a question for you. According to OP, both frames need to be able to update each other. So in this case, are you going to let both frames implement observer and observable at the same time (both frames become producer and consumer)? Since both needs to see changes from the other and both needs to notify changes for the other. Will the design be correct if we do that? Hope you can reply this.. – user3437460 Aug 29 '15 at 14:50
  • @user3437460 Actually, I'd recommend using a `JDialog` for the second window and when it's closed (via the okay button), obtain the value to be displayed on the second frame. But if required, a bi-directional observer pattern would be capable of updating both frames – MadProgrammer Aug 29 '15 at 21:24
  • 1
    How would the code of bi-directional observer pattern looks like in Java when there are 2 JFrames? Do you mind providing a solution if I ask a question on that? Anyway, thanks for replying. It is always good to see you around. – user3437460 Aug 31 '15 at 13:29
  • 1
    Well, it all comes down to needs. For example, the second frame my require an observer which has a "add" method to register a observer with it or you might have a controller which sits between then which manages the relationship – MadProgrammer Aug 31 '15 at 13:31
  • Please note Observable is deprecated in Java 9. You can use PropertyChangeListener instead. Event though not used in this example, my search led me here... – Miyagi Aug 31 '20 at 08:43
  • 1
    @Miyagi Please note, I rolled my own - `PropertyChangeListener` is just a form of the observer pattern ;) - The answer was intended more as an example of the principle – MadProgrammer Aug 31 '20 at 08:47