This question already has answers here:
The Use of Multiple JFrames: Good or Bad Practice? [closed]
(9 answers)
Closed 7 years ago.
My aim is for an action listener to close a specific JFrame when the user hits the JButton to quit.
Overall, when the program starts a large JFrame opens then a small one in front....in my code the user enters some details in this small one and hits submit(for the sake of simplicity, ive omitted this code here and replaced submit with quit)
So when this quit buttons pressed. I expect this small JFrame to close. I can't seem to figure this out. The action listeners in a different class and ive tried making instances and had no luck. I've commented out the code I've tried below when attempting to solve this issue.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class test
{
public static void main(String Args[])
{
makeGUI m = new makeGUI();
}
}
class makeGUI
{
JButton close = new JButton("CLOSE ME");
makeGUI()
{
frame f1 = new frame();
JFrame smallframe = new JFrame(); //want to close this one
JPanel jp = new JPanel(new FlowLayout());
smallframe.setSize(300,300);
smallframe.setLocationRelativeTo(null);
smallframe.setDefaultCloseOperation(smallframe.DISPOSE_ON_CLOSE);
close.addActionListener(new action());
jp.add(close);
smallframe.add(jp);
smallframe.setVisible(true);
}
class action implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
//makeGUI s1 = new makeGUI();
if (e.getSource () == close)
{
//s1.smallframe.dispose();
System.out.println("gotcha");
}
}
}
}
class frame extends JFrame
{
frame ()
{
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("big one");
setVisible(true);
}
}
First, it's not a good practice to name classes with a lowercase, so try renaming to something like MakeGUI instead of makeGUI.
The problem with your commented code is that it creates a new instance of makeGUI every time the button is clicked and the action listener is invoked. The result is that when you click on the close button, a new frame is created, then an inner one and this inner one gets immediately closed. The only thing you'd be doing is creating more and more frames. You should keep the instance as a state, for instance as a class member:
class MakeGUI {
JFrame smallframe;
JButton close = new JButton("CLOSE ME");
MakeGUI() {
frame f1 = new frame();
smallframe = new JFrame(); //want to close this one
JPanel jp = new JPanel(new FlowLayout());
smallframe.setSize(300, 300);
smallframe.setLocationRelativeTo(null);
smallframe.setDefaultCloseOperation(smallframe.DISPOSE_ON_CLOSE);
close.addActionListener(new action());
jp.add(close);
smallframe.add(jp);
smallframe.setVisible(true);
}
class action implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == close) {
// use this instead of dispose
smallframe.dispatchEvent(new WindowEvent(smallframe, WindowEvent.WINDOW_CLOSING));
System.out.println("gotcha");
}
}
}
}
If you want to simulate someone pressing the [X] button then you can use this code to programmatically trigger this event:
smallFrame.dispatchEvent(new WindowEvent(smallFrame, WindowEvent.WINDOW_CLOSING));
Aside from that, your code is not working because you are not closing your instance of the small window, instead you are creating another instance and disposing of it. Inside your close event you should be closing the smallFrame instance.
You can do this by either passing your JFrame to the constructor of your ActionListener or making smallFrame a class variable.
It appears you are using the small JFrame as a pop up to get information or display information. If so, you may want to look into the JOptionPane class which is made for "Dialogue Boxes".
Documentation:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JOptionPane.html
Related
I am trying to enter an event for JButon I create:
JButton botton1=new JButton("welcom to my show db! lets start");
botton1.setFont(new Font ("Eras Medium ITC",Font.BOLD,20));
this.add(botton1);
JPanel Basic_panel=new JPanel();
Basic_panel.setName("SHOW DB ");
Basic_panel.setBounds(x,y,width,hight);
botton1.addActionListener(this) ;
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==botton1){
Now I want to enter another JFrame I made, and make the first disappear. How?
For your original question:
How to add action to a button?
you might want to check How to write an Action Listener.
For your second question:
Now I want to enter another JFrame I made, and make the first disappear. How?
please check both approaches :)
Option 1 (Recommended)
If you want to do it the right way, you should use a CardLayout as recommended by #AndrewThompson in his comment above.
I also saw you were using a Null Layout (because of setBounds() method), you might also want to get rid of it, see Why is it frowned upon to use a null layout in Swing? and Null Layout is Evil to know why, insted you should be using a Layout Manager or combinations of them as shown in the following code based on #AndrewThompson's answer (The same that was linked in his comment above) but a bit modified to work with a JFrame instead of a JOptionPane, so give him credit by upvoting his Original Answer too!
This produces the following outputs:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
JButton button1, button2;
CardLayoutDemo() {
JFrame gui = new JFrame("CardLayoutDemo");
button1 = new JButton("Go to pane 2");
button2 = new JButton("Go to pane 1");
JPanel pane1 = new JPanel();
pane1.setLayout(new BoxLayout(pane1, BoxLayout.PAGE_AXIS));
JPanel pane2 = new JPanel();
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
pane1.add(new JLabel("This is my pane 1"));
pane1.add(button1);
pane2.add(new JLabel("This is my pane 2"));
pane2.add(button2);
gui.add(cards);
cards.add(pane1, "frame1");
cards.add(pane2, "frame2");
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == button1) {
cl.show(cards, "frame2");
} else if (ae.getSource() == button2) {
cl.show(cards, "frame1");
}
}
};
button1.addActionListener(al);
button2.addActionListener(al);
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.pack();
gui.setVisible(true);
}
public static void main(String[] args) {
new CardLayoutDemo();
}
}
With this option you only have 1 JFrame but you can change through different views, and you don't annoy user with multiple windows on the task bar.
One more tip here is: If you're going to open this second JFrame to prevent user from doing something on the 1st one, you should consider using a JOptionPane or this second JFrame will contain just a bit information which you don't want to have there for the whole time (Something like a pop up).
Option 2 (Not recommended)
But if you really really really want to use multiple JFrames (which is not recommended) you can dispose() it. At the time you're calling your new JFrame to be created. For example, the following code produces this output:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class TwoJFrames {
JFrame frame;
JButton button;
TwoJFrames() {
frame = new JFrame("1st frame");
button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new AnotherFrame();
frame.dispose();
}
});
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
new TwoJFrames();
}
class AnotherFrame {
JFrame frame2;
JLabel label;
AnotherFrame() {
frame2 = new JFrame("Second Frame");
label = new JLabel("This is my second frame");
frame2.add(label);
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.pack();
frame2.setVisible(true);
}
}
}
In this case you might want to consider setVisible() instead if you want to go back to previous state or reopen this one when closing the second JFrame
Both of my above codes are called a Minimal, Complete, and Verifiable example (MCVE) or Runnable Example or Short, Self Contained, Correct Example (SSCCE) which are code you can copy-paste and see the same output as me, when you have an error in your code, these examples are very handy because we can see where your errors are or be able to find them easier and/or faster.
You should consider reading all the links I provided (included these ones) and for your future questions to make something like I've done above, that way you'll prevent confusion and you'll get more, faster and better responses.
I am working on a LAB for one of my classes and am in need of some assistance.
I am building an Apartment Complex GUI which will have a menu system and individual functions between many different classes. The complex with consist of Tenants, Employees and a Bank.
I currently have the whole project working based out of the console but now I am assigned to convert it to a GUI interface.
This is the code in my main function for GUI:
ApartmentComplex mavPlace = new ApartmentComplex(); //creates a new apartment complex object
mavPlace.aptBank.setBalance(ANNUAL_BUDGET); //sets the apartment bank budget
readFile(mavPlace);
mavPlace.goThroughAndAssignValues(mavPlace);
JFrame frame = new JFrame("My First GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
JButton button = new JButton("Press");
frame.getContentPane().add(button); // Adds Button to content pane of frame
frame.setVisible(true);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
mavPlace.lease(mavPlace);
}
});
With the action listener, when the button is pressed it should call a lease function in another class of mine. From there I want it do go back to console output.
The error netbeans is giving me is: local variable mavPlace is accessed from within inner class; needs to be declared final
.... now I went an made the decleration final just to see what happened and it worked, but i couldnt edit my complex details so that was not possible.
What can i do?
Thank You!
Make your class implement the ActionListener interface and use this to add an action listener ie
button.addActionListener(this);
http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
If you use Anonymous Class, you should set the parameter used in the class as final type in current block or as a member private variable.
class MyGUI
{
ApartmentComplex mavPlace;
public MyGUI()
{
JFrame frame = new JFrame("My First GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
JButton button = new JButton("Press");
frame.getContentPane().add(button); // Adds Button to content pane of frame
frame.setVisible(true);
mavPlace = new ApartmentComplex(); //creates a new apartment complex object
mavPlace.aptBank.setBalance(ANNUAL_BUDGET); //sets the apartment bank budget
readFile(mavPlace);
mavPlace.goThroughAndAssignValues(mavPlace);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
mavPlace.lease(mavPlace);
}
});
}
}
I think you should reconsider your structure of your program.
If you told us the complete purpose, you would get better answer.
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.
G'day all,
I am coding a main menu for a project. The menu displays properly. I have also set up ActionListeners for the three buttons on the menu.
What I wish to do is reuse the JPanel for a new set of radio buttons when the user chooses "Start a New Game".
However, coding ActionPerformed to remove the existing components from the JPanel has me stumped. I know removeAll is somehow important, but unfortunately NetBeans informs me I cannot call it on my mainMenu JPanel object within ActionPerformed. So i have commented it out in my code below, but left it in so you can see what I am trying to do.
Your thoughts or hints are appreciated.
Here is my main code:
public class Main {
public static void main(String[] args) {
MainMenu menu = new MainMenu();
menu.pack();
menu.setVisible(true);
}
}
Here is my mainMenu code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
public MainMenu() {
super("RPG Main Menu");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainMenu = new JPanel();
mainMenu.setLayout(new FlowLayout());
startNewGame.setMnemonic('n');
loadOldGame.setMnemonic('l');
seeInstructions.setMnemonic('i');
startNewGame.addActionListener(this);
loadOldGame.addActionListener(this);
seeInstructions.addActionListener(this);
mainMenu.add(startNewGame);
mainMenu.add(loadOldGame);
mainMenu.add(seeInstructions);
setContentPane(mainMenu);
}
public void actionPerformed(ActionEvent evt) {
Object source = evt.getSource();
if (source == startNewGame) {
// StartNewGame code goes here
// mainMenu.removeAll();
}
if (source == loadOldGame) {
// LoadOldGame code goes here
}
if (source == seeInstructions) {
// Quit code goes here
}
}
}
Consider using a CardLayout instead, which manages two or more components (usually JPanel instances) that share the same display space. That way you don't have to fiddle with adding and removing components at runtime.
You need mainMenu to be a member variable:
public class MainMenu extends JFrame implements ActionListener {
JButton startNewGame = new JButton("Start a New Game");
JButton loadOldGame = new JButton("Load an Old Game");
JButton seeInstructions = new JButton("Instructions");
JPanel mainMenu = new JPanel();
Why do you feel the need to re-use this object?
You don't have a reference to mainMenu actionPerformed use. If you declare mainMenu with the buttons. It would work.
The problem is that the actionPerformed method is trying to call the JPanel mainMenu which is out of scope, i.e. the mainMenu variable is not visible from the actionPerformed method.
One way to get around this is to have the JPanel mainMenu declaration in the class itself and make it an instance field which is accessible to all instance methods of the class.
For example:
public class MainMenu extends JFrame implements ActionListener
{
...
JPanel mainMenu;
public MainMenu()
{
...
mainMenu = new JPanel();
...
}
public void actionPerformed(ActionEvent e)
{
...
mainMenu.removeAll();
}
}
Avoid attempting to "reuse" stuff. Computers are quite capable of tidying up. Concentrate on making you code clear.
So instead of attempting to tidy up the panel, simply replace it with a new one.
Generally a better way to write listeners is as anonymous inner classes. Code within these will have access to final variables in the enclosing scope and to members of the enclosing class. So, if you make mainMenu final and you ActionListeners anonymous inner classes, your code should at least compile.
Also don't attempt to "reuse" classes. Try to make each class do one sensible thing, and avoid inheritance (of implementation). There is almost never any need to extend JFrame, so don't do that. Create an ActionListener for each action, rather than attempting to determine the event source.
Also note, you should always use Swing components on the AWT Event Dispatch Thread. Change the main method to add boilerplate something like:
public static void main(final String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() { public void run() {
runEDT();
}});
}