0

In my program I have a main JFrame that holds a button. When this button is clicked a new JFrame appears in which I can change some information. Whenever I finish editing I press a save button on the new JFrame which saves the changes and disposes the JFrame. Now when this is done, I'd like to perform an action in the main JFrame as well, but only if something changed. If I open the new JFrame and just close it again without using the save button, I don't want to do anything in the main frame. I've tried searching the web for a solution, but just don't seem to be anything useful out there..

An example of the code I've got so far: Main Frame...


public class MainFrame extends JFrame
 {
     public MainFrame()
     {
         super("Main Frame");
         JButton details = new JButton("Add Detail");
         add(details);
         details.addActionListener(new ActionListener(){
             public void actionPerformed(ActionEvent e)
             {
                 new DetailFrame().setVisible(true);
             }
         });
     }
 }

Detail Frame...


 public class DetailFrame extends JFrame
 {
     public DetailFrame()
     {
         super("Detail Frame");
         JButton save = new JButton("Save");
         add(save);
         save.addActionListener(new ActionListener(){
             public void actionPerformed(ActionEvent e)
             {
                 // Save whatever content
                 dispose();
             }
         });
     }
 }

So when I click the "Save" button on the Detail Frame, I want to do something in the Main Frame, whereas when the "x" is clicked on the Detail Frame, I don't want to do anything..

Hope someone is able to help me, and sorry for my english..

Simon
  • 174
  • 4
  • 18

3 Answers3

2

You can pass a MainFrame handle to the DetailFrame constructor. Then, on clicking the Save button, the DetailFrame would call a function in MainFrame and pass the changes to it.

Another way is to create a public boolean variable in DetailFrame and set it to true when the Save button is clicked. This way MainFrame will know whether the DetailFrame was closed or Save'd.

EDIT: Some more ideas:

Use JDialog instead of JFrame. JDialog.setVisible is modal, i.e. it will block the calling function until the dialog is closed; this way you can process the results of the dialog in the same "Details" button listener.

To access the dialog after it is called, store the dialog in a separate variable. First construct the dialog, then show it, and then process the result by analyzing its variables.

Store the results of editing in other public variables of DetailFrame (or let's call it DetailDialog). This should happen only when the "Save" button is clicked. This may even allow to go without the boolean variable (depends on the types of values you are editing).

DetailDialog dlg = new DetailDialog();
dlg.setVisible(true);
if(dlg.approvedResult != null) {
    // process the result...
}

EDIT: Sorry, JDialog is not modal by default. Need to call a special super constructor to make it modal.

Also, here you will have to pass the reference to MainFrame to the dialog constructor, but you still can declare it as a simple JFrame and avoid unnecessary dependencies.

To get the reference to the enclosing MainFrame from within the anonymous ActionListener, use MainFrame.this.

To be able to change the button text after it was created, you will have to store the button in a member variable.

Main Frame...

public class MainFrame extends JFrame
{
    private JButton details = new JButton("Add Detail");

    public MainFrame()
    {
        super("Main Frame");
        getContentPane().add(details);
        details.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                DetailDialog dlg = new DetailDialog(MainFrame.this);
                dlg.setVisible(true);
                if(dlg.approved){
                    details.setText("Edit Detail");
                }
            }
        });
    }
}

Detail Dialog... (not Frame)

public class DetailDialog extends JDialog
{
    public boolean approved = false;

    public DetailDialog(JFrame parent)
    {
        super(parent,"Detail Dialog",true);        // modal dialog parented to the calling frame
        JButton save = new JButton("Save");
        getContentPane().add(save);
        save.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent e)
            {
                // Save whatever content
                approved = true;
                dispose();
            }
        });
    }
}
Goblin Alchemist
  • 829
  • 5
  • 11
  • I tried the thing with the public boolean value, but for some reason I just can't access it from the MainFrame.. I'm not sure what you mean by passing a handle to the DetailFrame constructer? – Simon Apr 23 '11 at 13:39
  • I edited the answer, please see more details above. In fact, passing the `MainFrame` to the dialog is not the best idea because it adds too many dependencies between classes; the method with public variables is better because it will allow you to use the same dialog in different places. – Goblin Alchemist Apr 23 '11 at 13:55
  • I tried the above now, but still doesn't work.. In my code the dialog doesn't seem to be modal - the function that opens the dialog keeps executing right away in stead of waiting until the dialog is closed.. – Simon Apr 23 '11 at 14:08
  • Finally got it working by calling the setModal(true) function before setting the dialog to be visible. – Simon Apr 23 '11 at 14:33
  • @Simon: "Finally got it working by calling the setModal(true)" That can be done in the constructor. BTW - The modality of the dialog was first mentioned in my reply. Did you miss that? – Andrew Thompson Apr 23 '11 at 21:56
  • @Andrew Thompson: sorry - I must have missed that.. I just figurer tis answer by Goblin was the Best description of the whole thing ;-) – Simon Apr 24 '11 at 07:20
0

Create the detail frame in the main frame, and add a windowlistener to it, using the windowadapter class. Implement the windowclosing event by checking for changes, handle those, and then dispose the detail frame. This is all done in the mainframe.

The detail frame should have do nothing on close set to prevent the detail frame being disposed before you recorded the changes.

You may wish to implement checking for changes in the detailframe as a method returning a class holding the interesting data. That way your windowlistener can be small an to the point.

extraneon
  • 23,575
  • 2
  • 47
  • 51
  • I don't quite get it.. The exact thing I want to do is, to change the text of the "Add Detail" button to say "Edit detail", but only when a detail is added.. Could you by any chance give a code example of what you described above? – Simon Apr 23 '11 at 13:38
0

Forget the 2nd JFrame. use a modal dialog instead. It will block input until dismissed. Once dismissed, the only thing to do is decide whether to update the original data. JOptionPane has some inbuilt functionality that makes that easy. If the user presses Cancel or the esc key, the showInputDialog() method will return null as the result.

import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

class EditInfo {

    public static void main(String[] args) {

        Runnable r = new Runnable() {
            public void run() {
                final JFrame f = new JFrame("Uneditable");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

                JPanel p = new JPanel(new BorderLayout(10,10));

                final JTextField tf = new JTextField("Hello World!", 20);
                tf.setEnabled(false);
                p.add(tf, BorderLayout.CENTER);

                JButton edit = new JButton("Edit");
                edit.addActionListener( new ActionListener(){
                    public void actionPerformed(ActionEvent ae) {
                        String result = JOptionPane.showInputDialog(
                            f,
                            "Edit text",
                            tf.getText());
                        if (result!=null) {
                            tf.setText(result);
                        }
                    }
                } );
                p.add(edit, BorderLayout.EAST);

                p.setBorder(new EmptyBorder(10,10,10,10));

                f.setContentPane(p);
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

If it is necessary to edit a number of fields all at once in the JOptionPane, use a JPanel to contain them all, and put them in a showMessageDialog() call. Check the integer based return result to determine if the user OK'd the changes.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433