I have a jframe object in a class and I want to be able to close the frame from my jpanel class(which obviously I attach to the frame). Anyway, I tried making a instance field in my jpanel with the jframe object has an instance field and then made a method that I would call in the jframe class with the parameter of the jframe object I made so I could make the jpanel instance field the same object as the jframe object. I then called the instance field.dispose(); hoping it would close the frame. Any ideas would be greatly appreciated!
In case that was hard to understand here is an example:
public class example extends jFrame
{
public static void main(String[]args)
{
examplePanel ep = new examplePanel();
example e = new example(ep);
}
/**
* Constructor for objects of class example
*/
public example(examplePanel ep)
{
//code that handles my frame settings
}
}
public class examplePanel extends jPanel implements ActionListener
{
private example e;
private boolean checkWin;
public void actionPerformed(ActionEvent e)
{
if(this.checkWin())
{
setVisible(false);
e.dispose();
//^this line of code is supposed to dispose of the frame but it does not
}
}
public void getExample(example e)
{
this.e = e;
}
}
Your code and question are hard to follow as you have an ActionListener which you add to no JButton or JMenuItem, You create a JFrame object and a JPanel, but are never observed to add the panel to the frame. You give your JPanel an "example" variable, but never assign it a reference to the visualized JFrame, you don't appear to ever set the default close operation of the JFrame, and so your JFrame as written above should be non-closable. From your code it looks like your examplePanel's e variable in the JPanel should in fact be null and so calling any method on it should throw a NullPointerException, that is unless you're assigning the correct JFrame object reference to it, but are not showing us.
Myself, I'd get the top level window from Swing itself when needed, something like:
#Override
public void actionPerformed(ActionEvent e) {
// get the top-level window that is displaying this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose(); // dispose of it
}
}
For example:
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.*;
import javax.swing.*;
public class CloseFromJPanel extends JPanel implements ActionListener {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
public CloseFromJPanel() {
JButton closeButton = new JButton("Close Me");
closeButton.addActionListener(this);
add(closeButton);
}
#Override
public void actionPerformed(ActionEvent e) {
// get the top-level window that is displaying this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose(); // dispose of it
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Close From JPanel");
// GUI will exit when the JFrame is closed
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CloseFromJPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This code will work for JButtons within JFrames and JDialogs, but not JMenuItems or within JApplets (I don't think). Or if all you want to do is end the application, then you could simply call System.exit(0) from within the actionPerformed method. If you absolutely want to do this using a field of the JFrame, then you'll need to pass in a reference to the JFrame into the JPanel, likely using a constructor parameter, and possibly passing in this.
If this doesn't help, please create and post real code, not kind-of sort-of code, code that we can compile, run and actually test, an MCVE (please check out the link).
Other issues:
Your code does not comply with Java naming standards as class names should all start with capital letters. Please Google this and study it, since if your code follows standards, others, including both us and your future self, will better be able to understand your code.
You'll rarely want to ever extend from JFrame since you rarely need to alter it's innate behavior. Usually you'll create and use a JFrame or JDialog when and where needed.
Related
I am trying to implement mouse listener however I can not seem to get it to work. My code doesnt have any errors, but when I click on the frame I I can not get a message to print out. I have tried extending the class HandleClassOne to viewOne, but that also wouldn't work. Any thoughts?
The main class creates a frame and then creates an instance of viewOne on the frame.
public class main{
protected static JFrame window;
public static void main(String args[]){
window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400,400);
window.setVisible(true);
new viewOne(window);
}
}
The viewOne class adds a panel and a label to a frame. It also adds a mouse listener to the panel.
public class viewOne {
private static JPanel panel1;
private static JLabel label1;
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
frame.validate();
}
public static void mouseAdd() {
HandleClassOne handle = new HandleClassOne();
panel1.addMouseListener(handle);
panel1.addMouseMotionListener(handle);
}
public static void main(String[] args) {
mouseAdd();
}
}
The HandleClassOne class should print out a message when the panel created in viewOne is clicked.
public class HandleClassOne extends main implements MouseListener, MouseMotionListener {
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked");
}
}
While you have defined the function mouseAdd(...) I don't see you calling it.
Try (within the constructor)
public viewOne(JFrame frame) {
...
mouseAdd();
...
}
naturally, you'll need to do this after the panel1 is set.
Note that there are other issues, too
You don't invoke presenting the JFrame properly within your main function in your main class. Look up a basic tutorial on Java Swing, where it talks about the event dispatch thread and the requirements to not present within your program's main thread of execution.
You have an additional main function in your viewOne class, which is not how these things are wired up.
You added the mouseAdd() method (which is responsible for registering the mouse listener) inside the main method of viewOne class.
Please keep in mind that main method only gets called whenever you are running it as entry point class for your application. Here you have main class to act as an entry point.
You kept main method in viewOne class as well and it will get called only when you are running it as an individual piece (not along with main class).
To fix the issue here, keep your mouseAdd() method call inside viewOne() constructor as constructor gets called every time whenever object is getting created.
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
mouseAdd();
frame.validate();
}
I would like some clarity on what is exactly happening here. Say I have these three methods and I continually hit the button again and again. Is this causing some kind of memory leak or chain of pointers that I am unaware of? My understand is that when a method ends any variables local to that method are cleaned up. This would include that "pointer" to the new JFrame then correct?
Again assume the user is clicking the button on each frame.
public class driver {
public static void main(String[] args) {
// TODO Auto-generated method stub
parentFrame pF = new parentFrame();
}
}
-
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class parentFrame extends JFrame {
private JFrame frame;
private JButton button;
public parentFrame() {
frame = new JFrame("Parent Frame");
frame.setSize(400, 400);
button = new JButton();
frame.add(button);
button.addActionListener(new buttonPress());
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void createChild() {
#SuppressWarnings("unused")
childFrame cF = new childFrame(); //The default constructor will display the frame
frame.dispose(); //How?
}
class buttonPress implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
createChild();
}
}
}
-
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class childFrame extends JFrame {
private JFrame frame;
private JButton button;
public childFrame() {
frame = new JFrame("Child Frame");
frame.setSize(400, 400);
button = new JButton();
frame.add(button);
button.addActionListener(new buttonPress());
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void createParent() {
parentFrame pF = new parentFrame(); //The default constructor will display the frame
frame.dispose(); //How?
}
class buttonPress implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
createParent();
}
}
}
I'm not sure what you mean by "I don't have to call super()", but if you want to avoid confusion, then either extend JFrame or use a variable in your class of type JFrame. You have both, and create the variable reference in the constructor, so that when JFrame frame = new parentFrame(); is executed, two JFrames are created: the one on which you have the new operator, and the one in the constructor of that object.
As for cleanup, when you execute setVisible(true); on a JFrame, it seems obvious to me that the JFrame reference gets put into the Swing system, and so the variable in your method (whether local or instance (or static)) is no longer the only reference. I think of dispose() as an instruction to the Swing framework that the code is done with this variable, clean up after it and remove all references to it. If you don't do that before you lose your own reference to the variable (e.g., if it were a local variable and you didn't do that before you exited the method), then you would lose your chance to call dispose. I suppose you could still get a reference from Swing somehow, and then call dispose on it.
You don't say whether you have evidence of a memory leak or or just trying to understand this code.
I have read your question, the answers and the comments. I advice you to review OOP basics to link your objects better. About the comment:
How can I create a new Frame in the parentFrame and then dispose of that frame but the child frame remains alive. Is control passed to the child frame?
Each JFrame is an independent instance of the JFrame object. You don't need to manually pass control. What you should do is define closing behaviour for each JFrame: A main frame on close will close the whole program (EXIT_ON_CLOSE), secondary frames can have other behaviour (HIDE_ON_CLOSE or DISPOSE_ON_CLOSE). You define this with:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
I should advice you to go through the java tutorials and make sure you understand well about classes and instances before diving into swing. Start manually will help you understand better (I saw they told you this already but I agree on it). Keep on!
I'm kind of confused. I'm at work right now (just started apprenticeship) and need to create a fully editable table (I'll use SQL soon). So I have 2 questions here:
What do you mean by "Don't extend JFrame"? Let's say I have a class called "TestDialog" and also a JFrame which is called "TestUI". Would it be okay to write
public class TestDialog extends TestUI ?
As I have understood it, one shouldn't create a class (called MyExample) and inside of this class just write
public class MyExample extends JFrame
Because you create a JFrame within an existing class instead of creating it seperate.
I'll keep it short - Can I use 2 actions in 1 listener (for 1 button)? Something like:
public void actionPerformed(ActionEvent e)
{
Action_One; Action_Two;
}
Or do I need to use 2 different listeners?
Okay that's it I guess. I'm sorry that I haven't written everything clearly, I just registered here and actually concentrate on translating things from my language into english. If anyone could tell me how to write here like in Eclipse I'd appreciate it, because I couldn't really find out how.
Composition over inheritance is an important programming approach. So I preffer following construction of GUI.
public class Application {
private JFrame mainFrame;
private MainPanel mainPanel;
private void installFrame() {
// initialize main frame
mainFrame = new JFrame("Title");
}
private void installComponents() {
// install all components
mainPanel = new MainPanel();
}
private void layout() {
// provide layouting
mainFrame.add(mainPanel.getComponent());
}
private void show() {
mainFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Application app = new Application();
app.installFrame();
app.installComponents();
app.layout();
app.show();
}
});
}
}
Main panel has no inheritance from JPanel, but use an instance of it.
public class MainPanel {
private JPanel mainPanel;
public MainPanel() {
mainPanel = new JPanel(new GridBagLayout()); // or another layout
initComponents();
layout();
}
private void initComponents() {
// init all components here
}
private void layout() {
// layout panel here
}
public Component getComponent() {
return mainPanel;
}
}
The same pattern I use for each complex component (for example for trees, tables, lists, tabbed panes etc.). But this approach has one disadvantage: there is no GUI builder that support it.
About actions: you can provide a combined action. Something like this
public class CombinedAction extends AbstractAction {
private Action[] delegates;
public CombinedAction(String name, Icon icon, Action... someDelegates) {
super(name, icon);
delegates = someDelegates;
}
public void actionPerformed(ActionEvent ae) {
for (Action delegate : delegates) {
delegate.actionPerfromed(ae);
}
}
}
What do you mean 2 actions? You can do anything in the actionPerformed() method. If instead your question is "can I have 2 actionPerformed methods in the class" ie two actionListeners then it's a 'NO'. You must instead read on Inner Classes to do that.
And regarding your first question it's more of a design issue.
I would prefer
public class Example{
JFrame frame;
public void initialize()
{
frame.setSize(//params);
frame......
//other frame initilizing code
}
public static void main(string[] args)
{
Example example=new Example();
example.initialize();
}
}//class ends
while someone else may feel otherwise
I have a button in my GUI that is supposed to close its window. However, its event handler is located in an AbstractAction subclass that is located in a seperate method from the JFrame. Because of this I cannot see a way to tell the JFrame to close from my AbstractAction.
Heres the basic layout of my code:
public PointWindow()
{
initialize();
}
public void initialize()
{
JFrame frame = new JFrame();
// JFrame stuff
frame.setContentPane(createGUI());
frame.setVisible(true);
}
public JPanel createGUI()
{
JPanel gui = new JPanel();
// Code....
class MakeGraphACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
frame.setVisible(false); // <--- How to get this to work?
frame.dispose(); // <---
new GraphWindow(pointList);
}
}
//Code...
return gui;
}
Have I done a bad job planning my code or am I just missing something obvious?
You need to pass the frame as a final parameter to the createGUI() method.
You will then be able to access it from within the inner class.
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();
}});
}