So this is probably a silly question but I just cant figure it out.
Basically I have my MainWindow, when I press a button a new window should appear named PartSelectionWindow that contains a JTable (the JTable is filled out with a custom table model). Then I select a row and press ok to go back to the MainWindow and work with the info selected. Here's the problem:
If I use a JFrame for the PartSelectionWindow, after the window is closed the code execution does not continue in the MainWindow button event
If i use a JDialog, the Jtable is not filled out with the custom model and the button for it does not respond, it can only be closed by clicking on the X of the JDialog. It's as if it was disabled. When debugging I noticed it DOES try to fill out the table AFTER closing the JDialog. I read somewhere that this may be because the code is paused after the setVisible is set to true, so I tried putting the code to fill out the JTable BEFORE the setVisible is set to true but it still does not work.
Obligatory code:
//MainWindow button event when tryng to use new JFrame
private void btnSetupListActionPerformed(java.awt.event.ActionEvent evt) {
//call to new JFrame
new partsWindow();
//after closing partsWindow the next line of code does NOT execute
txtPartNum.setText(PartsWindow.jpart.getPartNumber());
}
//MainWindow button event when tryng to use new JDialog
private void btnSetupListActionPerformed(java.awt.event.ActionEvent evt) {
//call to new JDialog
new partsDialog(this, true);
//after closing partsWindow the next line of code does NOT execute
txtPartNum.setText(PartsWindow.jpart.getPartNumber());
}
Constructor for JDialog window
public partsDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
this.setTitle("Setup Material Client");
this.setVisible(true);
this.setLocationRelativeTo(null);
jTable1.getTableHeader().addMouseListener(new partsDialog.ColumnFitAdapter());
jTable1.getTableHeader().setReorderingAllowed(false);
GetBomForSetupMaterial = jtrace.GetBomForSetupMaterial(Main.station);
jTable1.setModel(new PartModel(GetBomForSetupMaterial.getPartPositionList()));
}
Any help would be appreciated.
To ilustrate my comment you can use code like this (simplified)
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class JDialogTest extends JDialog {
private static final long serialVersionUID = 1L;
private String text;
private JTextField textField;
public JDialogTest(JFrame owner, String text){
super(owner,true);
this.text = text;
init();
}
private void init() {
this.getContentPane().setLayout(new BorderLayout());
JButton btnContinue = new JButton("Close me and continue");
btnContinue.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JDialogTest.this.dispose();
}
});
textField = new JTextField();
this.getContentPane().add(new JLabel(text),BorderLayout.NORTH);
this.getContentPane().add(textField,BorderLayout.CENTER);
this.getContentPane().add(btnContinue,BorderLayout.SOUTH);
this.pack();
}
public JTextField getTextField() {
return textField;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
JDialogTest test = new JDialogTest(frame, "Hello");
System.out.println("I open");
test.setLocationRelativeTo(null);
test.setVisible(true);
System.out.println("Good you closed it value is " + test.getTextField().getText());
frame.setVisible(false);
}
}
I just passed some text to end up in JLabel you should pass your table or info on how to create it
For the second window, do frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) or something like that. I'm on my phone so i can't get the exact code. This line of code will make it so the frame will be terminated, not the program
In your main window make it a JFrame. When it is constructed create your dialog in there but set its visible to false. The dialog should be modal = false. When you set this as false the main window will wait until the JDialog is no longer visible to continue its code execution:
Public class MainWindow extends JFrame {
protected JDialog = yourDialog;
public MainWindow {
yourDialog = new JDialog(this, false);
//* rest of your construction *//
}
private void yourButtonPressedActionPreformed(java.awt.eventActionEvent evt) {
yourDialog.setVisible(true);
//* The code halted here until you have set the visibility of that dialog to false.
Make the dialog do that to itself when the button is pressed *//
foobar = yourDialog.getYourData();
}
Setting the JDialog modal to false will cease the code operation in your main window until it is done but since you have only set its visibility to false you can still grab data from it as you need.
Related
I have 2 jframes, 1 is kinda like the main menu, i want an attribute to change in the level jframe when a button is pressed so i tried:
SpeelVeld frame = new SpeelVeld();
frame.level = 1;
System.out.println(frame.level);
I used the sout to see what really happens because it wasnt working, but i see that the level goes from 0 to 1 back to 0 and goes on and on, does someone know why and how to fix?
SpeelVeld frame = new SpeelVeld();
frame.setBounds(0,0,519,591);
frame.setLocationRelativeTo(null);
frame.getContentPane().setBackground(Color.WHITE);
frame.setTitle("RWINA");
frame.setVisible(true);
frame.setLevel(1);
this is in the main method of my original GameProject file.
How can i make a jdialog
I have 2 jframes, 1 is kinda like the main menu,
You shouldn't use 2 JFrames for this. The dependent sub-window, likely your main menu window, should in fact be a JDialog, probably a non-modal dialog from the looks of it.
I want an attribute to change in the level jframe when a button is pressed so i tried:
SpeelVeld frame = new SpeelVeld();
frame.level = 1;
System.out.println(frame.level);
and here's a big problem. Understand that in this code, you're creating a new SpeelVeld object, the stress being on the word new. Changing the state of this object will have no effect on the other SeelVeld object that is currently being displayed. Do do that, your second window will need a valid reference to the displayed SeelVeld object. How to do this will depend all on code not yet shown, but often it can be done simply by passing in the displayed SpeelVeld object into the main menu object by use of a constructor parameter or setter method.
For example:
import java.awt.Dialog.ModalityType;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
// JPanel for our main GUI
public class SpeelVeldFoo {
private static void createAndShowGui() {
// JPanel used by the main JFrame
SpeelVeldPanel speelVeldPanel = new SpeelVeldPanel();
// JPanel used by the main menu JDialog. Pass the above into it
MainMenuPanel mainMenuPanel = new MainMenuPanel(speelVeldPanel);
// create your JFrame
JFrame frame = new JFrame("Speel Veld");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(speelVeldPanel); // add the JPanel
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
// create your non-modal JDialog
JDialog menuDialog = new JDialog(frame, "Main Menu", ModalityType.MODELESS);
menuDialog.add(mainMenuPanel); // add the JPanel that holds its "guts"
menuDialog.pack();
menuDialog.setLocationByPlatform(true);
menuDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class SpeelVeldPanel extends JPanel {
private int level = 1; // simple example just has a level int
private JLabel levelLabel = new JLabel("1"); // and displays it in a JLabel
public SpeelVeldPanel() {
add(new JLabel("Level:"));
add(levelLabel);
int ebGap = 50;
setBorder(BorderFactory.createEmptyBorder(ebGap, 2 * ebGap, ebGap, 2 * ebGap));
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
// whenever level is changed, update the display
this.level = level;
levelLabel.setText(String.valueOf(level));
}
}
// class for the JPanel held by the JDialog
#SuppressWarnings("serial")
class MainMenuPanel extends JPanel {
private JSpinner levelSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 5, 1));
private SpeelVeldPanel speelVeldPanel = null; // reference to the main GUI
// note the parameter.... you pass in the displayed main GUI so you can
// change it
public MainMenuPanel(final SpeelVeldPanel speelVeldPanel) {
this.speelVeldPanel = speelVeldPanel; // set the field
// respond when the spinner's data changes
levelSpinner.addChangeListener(new LevelListener());
add(new JLabel("Set the Speel Veld's level:"));
add(levelSpinner);
int ebGap = 10;
setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
}
private class LevelListener implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
// when the spinner's data changes
int level = (int) levelSpinner.getValue(); // get the data
speelVeldPanel.setLevel(level); // and send it to the main GUI
}
}
}
You'll note that I don't like extending JFrame or JDialog if I can avoid it. My feeling is that one can paint oneself into a corner by having your class extend JFrame, forcing you to create and display JFrames, when often more flexibility is called for. More commonly your GUI classes will be geared towards creating JPanels, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. This will greatly increase the flexibility of your GUI coding.
You probably want the JFrame to be the top-level container, then have a JPanel that holds your menu. The menu could be whatever you want, I'm using a JTextArea. Then, you need a JButton for the JPanel or JFrame that when pressed, changes the text in the JTextArea. Here is an implementation that you could work from. I'm using the ActionEvent as the trigger for when to mess with the JTextArea:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class SimpleSwing {
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
JPanel mainMenuPanel = new JPanel();
JTextArea textAttribute = new JTextArea("Original Text");
JButton changeAttributeButton = new JButton("Change Attribute");
changeAttributeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textAttribute.setText("Whatever new text you want");
}
});
mainMenuPanel.add(textAttribute);
mainMenuPanel.add(changeAttributeButton);
mainFrame.add(mainMenuPanel);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(500, 500);
mainFrame.setVisible(true);
}
}
I have a code that opens up a JOptionPane dialog box once the user hits a button. The first thing I want to do is close the first JFrame as soon as the user hits one of the buttons. I have tried doing this
setVisible(false); // Delete visibility
dispose(); //Delete window
but the original JFrame doesn't close as soon as a button is pressed. The goal is to have two buttons. When one is pressed, show a JOptionPane box, while simultaneously closing the first JFrame window. How can I do that? Next, after the ok is pushed in the new JOptionPane I wan't to stimulate what would be an action listener. I do this by calling the method
sinceyoupressedthecoolbutton();
right after my JOptionPane declaration. Here is where the second issue starts, it displays the JOptionPane perfectly, but doesn't go to the method
sinceyoupressedthecoolbutton();
I don't know if the problem is in the method calling or the content of the method. Basically, after ok is pressed on the JOptionPane, I wan't to move to another method, which opens a new JLabel.
Here is the code:
package Buttons;
import java.awt.Dimension;
import java.awt.FlowLayout; //layout proper
import java.awt.event.ActionListener; //Waits for users action
import java.awt.event.ActionEvent; //Users action
import javax.swing.JFrame; //Window
import javax.swing.JLabel;
import javax.swing.JButton; //BUTTON!!!
import javax.swing.JDialog;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane; //Standard dialogue box
public class ButtonClass extends JFrame {
private JButton regular;
private JButton custom;
public ButtonClass() { // Constructor
super("The title"); // Title
setLayout(new FlowLayout()); // Default layout
regular = new JButton("Regular Button");
add(regular);
custom = new JButton("Custom", b);
add(custom);
Handlerclass handler = new Handlerclass();
Otherhandlerclass original = new Otherhandlerclass();
regular.addActionListener(handler);
custom.addActionListener(original);
//THIS WAS MY FIRST PROBLEM, I WANT TO CLOSE THE FIRST JFRAME WINDOW AS THE USER HITS OK
setVisible(false); // Close the show message dialog box
dispose();
}
public class Handlerclass implements ActionListener { // This class is
// inside the other
// class
public void actionPerformed(ActionEvent eventvar) { // This will happen
// when button is
// clicked
JOptionPane.showMessageDialog(null, String.format("%s", eventvar.getActionCommand())); //opens a new window with the name of the button
}
}
public class Otherhandlerclass implements ActionListener {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null,"Since you pressed that button, I will open a new window when you press ok, okay?");
//Code works up until here
sinceyoupressedthecoolbutton(); //THIS METHOD SHOULD OPEN A NEW WINDOW!
}
public void sinceyoupressedthecoolbutton() {
JDialog YES = new JDialog();
JLabel label = new JLabel("Here is that new window I promised you!");
add(label);
YES.setDefaultCloseOperation(JDialog.EXIT_ON_CLOSE);
YES.setSize(500, 500);
YES.setVisible(true);
}
public class okay implements ActionListener {
public void actionPerformed(ActionEvent ok) {
}
}
}
}
Help would be appreciated!
You're working in a Event Driven Environment, not a linear processing one. This means that you run some code and then wait (the waiting is done for you) for some event to occur and then you respond to it...
Nothing can happen till the user presses the custom button, so it's pointless trying to close the frame before then
When your Otherhandlerclass's actionPerformed is triggered, obviously you show the JOptionPane pane, this will block the flow of the execution until it's closed. At this point, you should have the opportunity to the dispose of the original window.
So instead of calling setVisible(false) and dispose in your constructor, it would be better to move it to Otherhandlerclass
public class Otherhandlerclass implements ActionListener {
public void actionPerformed(ActionEvent e) {
dispose();
JOptionPane.showMessageDialog(null, "Since you pressed that button, I will open a new window when you press ok, okay?");
sinceyoupressedthecoolbutton();
}
public void sinceyoupressedthecoolbutton() {
JDialog YES = new JDialog();
JLabel label = new JLabel("Here is that new window I promised you!");
YES.add(label);
YES.setSize(500, 500);
YES.setVisible(true);
}
public class okay implements ActionListener {
public void actionPerformed(ActionEvent ok) {
}
}
}
Having said that, I'd encourage you to have a read of The Use of Multiple JFrames, Good/Bad Practice? and maybe consider using something like How to Use CardLayout instead
I'm working on a program which has multiple JFrame and JDialog windows.
I have a JFrame which contains a button, when I click on this button a JDialog window opens up. In this JDialog windows there is another button, which when is clicked it opens up a second JDialog window. In the second JDialog window I have a last button.
What I want to do is to close both JDialog windows and JFrame window when this last button is clicked.
This is how the opening order is:
JFrame Frame1;
JButton Button1;
JDialog Dialog1;
JButton Button2;
JDialog Dialog2;
JButton Button3;
Button1ActionPerformed(ActionEvent e){
new Dialog(Frame1Frame);
}
Button2ActionPerformed(ActionEvent e){
new Dialog2(Dialog1Frame)
}
Button3ActionPerformed(ActionEvent e){
//Here I wnat to add the code that closes JDialog2 JDialog1 and JFrame1 windows.
}
I have tried super.dispose(); but it doesn't work. Any ideas?
As shown here using Action, your actionPerformed() implementation can dispatch the WINDOW_CLOSING event to the desired Window instances.
#Override
public void actionPerformed(ActionEvent e) {
d1.dispatchEvent(new WindowEvent(d1, WindowEvent.WINDOW_CLOSING));
d2.dispatchEvent(new WindowEvent(d2, WindowEvent.WINDOW_CLOSING));
f1.dispatchEvent(new WindowEvent(f1, WindowEvent.WINDOW_CLOSING));
}
There may be better ways of doing this, but here is one general approach that might help.
In your code you create the windows but you do not store the reference to the windows you created into a variable. For example, you have:
JDialog Dialog1;
Then later, when you create the instance of Dialog1, you have this code:
Button1ActionPerformed(ActionEvent e){
new Dialog(Frame1Frame);
}
This means you have created the Dialog, but you have not retained a reference to the Dialog for later manipulation by your code. If you assign this value here, you should be able to manipulate it later.
If you change your implementation to:
Button1ActionPerformed(ActionEvent e){
Dialog1 = new Dialog(Frame1Frame);
}
Then later in your code you will have a reference to the Dialog in order to manipulate it,
Button3ActionPerformed(ActionEvent e){
Dialog1.dispose();
// you can manipulate the variables of the class from here and close other windows etc.
}
If you have the objects reference, you can do:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class Main
{
private static JFrame frame;
private static JButton buttonFrame;
private static JDialog dialog1;
private static JButton buttonDialog1;
private static JDialog dialog2;
private static JButton buttonDialog2;
public static void main(String[] args) {
/* frame */
frame = new JFrame("Main Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
buttonFrame = new JButton("open dialog 1");
buttonFrame.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
dialog1.setVisible(true);
}
});
frame.add(buttonFrame);
/* dialog 1 */
dialog1 = new JDialog(frame, "Dialog 1");
dialog1.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog1.setSize(300, 300);
dialog1.setLocationRelativeTo(null);
buttonDialog1 = new JButton("open dialog 2");
buttonDialog1.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
dialog2.setVisible(true);
}
});
dialog1.add(buttonDialog1);
/* dialog 2 */
dialog2 = new JDialog(dialog1, "Dialog 2");
dialog2.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog2.setSize(200, 200);
dialog2.setLocationRelativeTo(null);
buttonDialog2 = new JButton("close all");
buttonDialog2.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
dialog2.dispose();
dialog1.dispose();
frame.dispose();
}
});
dialog2.add(buttonDialog2);
/* show frame */
frame.setVisible(true);
}
}
Otherwise you can use System.exit(0);:
buttonDialog2.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
Closing multiple JFrame by another JFrame-
It is possible to close multiple windows, even non-static Java swing windows. Type below small code, step by step.
The below code is mainly for closing the First frame through the second open frame which has been opened by the same First frame.
*Make a **second class global variable** in the first-class & a **button global variable in first-class*
Class2 NiceApp1 = new Class2();
JToggleButton Nice=new JToggleButton("Nice One");
// *After the Class1 above code, you will need a close method. I use a jar of NiceApplication1 with class New Close you can use the same jar or very below close method and can call the close method. You will need to type the method in Class1, just type your **close method in the method**.*
public void method (){
NewClose NiceO = new NewClose();
NiceO.Close(this);
//or
Close();
}
*// Now make a **Button Global variable in Class2**.*
javax.swing.JToggleButton Zero = new javax.swing.JToggleButton();
*// Type in Class2 the below **method**.*
public void methodclass2(JToggleButton Nice){
Zero = Nice;
}
*//Now you will need to type the below code, type the below code in the **Class1 button action** by which you will open the Class2.*
Nice.addActionListener((ActionEvent e) -> {
method();
});
NiceApp1.methodclass2(Nice);
NiceApp1.setVisible(true);
*//Now just type a **single line code** in the second class, type anywhere from which you want to close Class1.*
Zero.doClick();
*//Now the **close method** if you don't have a close method.*
public void Close() {
WindowEvent winclosing = new WindowEvent(this, WindowEvent.WINDOW_CLOSING);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(winclosing);
}
**You have done now if you did the above process.
If you only want to close which opens secondly so by the only close method change the this into your frame variables.
You can also visit NiceApplication1.BlogSpot.Com.
You can use the above code. From Class2 after the button's click, you will see your previous Class1 window will close.**
I have two Jframes where frame1 has some text fields and when a button on frame1 is clicked, I open another JFrame which contains a search box and a JTable containing search results.
When I click on a result row on JTable, I want that particular values to be reflected in the frame1 text fields.
I tried passing the JFrame1's object as a parameter but I have no clear idea on how to achieve this.
Any help would be highly appreciated.
Thanks
First of all, your program design seems a bit off, as if you are using a JFrame for one of your windows where you should in fact be using a JDialog since it sounds as if one window should be dependent upon the other.
But regardless, you pass references of GUI objects the same as you would standard non-GUI Java code. If one window opens the other (the second often being the dialog), then the first window usually already holds a reference to the second window and can call methods off of it. The key often is when to have the first window call the second's methods to get its state. If the second is a modal dialog, then the when is easy -- immediately after the dialog returns which will be in the code immediately after you set the second dialog visible. If it is not a modal dialog, then you probably want to use a listener of some sort to know when to extract the information.
Having said this, the details will all depend on your program structure, and you'll need to tell us more about this if you want more specific help.
For a simple example that has one window open another, allows the user to enter text into the dialog windows JTextField, and then places the text in the first window's JTextField, please have a look at this:
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class WindowCommunication {
private static void createAndShowUI() {
JFrame frame = new JFrame("WindowCommunication");
frame.getContentPane().add(new MyFramePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// let's be sure to start Swing on the Swing event thread
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MyFramePanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton openDialogeBtn = new JButton("Open Dialog");
// here my main gui has a reference to the JDialog and to the
// MyDialogPanel which is displayed in the JDialog
private MyDialogPanel dialogPanel = new MyDialogPanel();
private JDialog dialog;
public MyFramePanel() {
openDialogeBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openTableAction();
}
});
field.setEditable(false);
field.setFocusable(false);
add(field);
add(openDialogeBtn);
}
private void openTableAction() {
// lazy creation of the JDialog
if (dialog == null) {
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
dialog = new JDialog(win, "My Dialog",
ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(dialogPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
}
dialog.setVisible(true); // here the modal dialog takes over
// this line starts *after* the modal dialog has been disposed
// **** here's the key where I get the String from JTextField in the GUI held
// by the JDialog and put it into this GUI's JTextField.
field.setText(dialogPanel.getFieldText());
}
}
class MyDialogPanel extends JPanel {
private JTextField field = new JTextField(10);
private JButton okButton = new JButton("OK");
public MyDialogPanel() {
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
okButtonAction();
}
});
add(field);
add(okButton);
}
// to allow outside classes to get the text held by the JTextField
public String getFieldText() {
return field.getText();
}
// This button's action is simply to dispose of the JDialog.
private void okButtonAction() {
// win is here the JDialog that holds this JPanel, but it could be a JFrame or
// any other top-level container that is holding this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose();
}
}
}
You'd do a very similar technique to get information out of a JTable.
And again, if this information doesn't help you, then please tell us more about your program including showing us some of your code. The best code to show is a small compilable example, an SSCCE similar to what I've posted above.
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..
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();
}
});
}
}
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.
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.