I don't understand a feature of the inner class CHameleon. I don't get what line 8 in theory means.
I think it means to produce a duplicate version of JFrame that will be accessed outside of the inner class, in order to manipulate the intended JFrame object.
Edit: Code brings a null pointer exception error because JFrame object is never referenced.
Solution: modify JFrame frame to final JFrame frame.
This brings up the question on what if there were multiple JFrames?
For example, if I had a class garden with different veggies, and I created an inner class colorsplat that colors these veggies. Is the only solution to create specific classes that target specfic veggies? So to answer my own question, in the case of multiple JFrames, they would appear as different kinds of classes, my case?
public class LabelsButtonsPanelsandSnakes {
public static void main(String[] args){
final JFrame frame = new JFrame("Test");
JMenuBar menuBar = new JMenuBar(); //menubar
JMenu menu = new JMenu("Menu");
JMenuItem chameleon = new JMenuItem("Change Color");
class CHameleonaction implements ActionListener{ //inside class opens
JFrame frameHolder; //line 8
public void actionPerformed(ActionEvent e)
{
frame.getContentPane().setBackground(new Color(112,253,95));
}
} //inside class ends
chameleon.addActionListener(new CHameleonaction());
menuBar.add(menu);
frame.setJMenuBar(menuBar);
}
You're doing way too much within your main method, and most of this code belongs elsewhere since the main method should be used to mainly create your main objects and start them running, but little else. As noted in my comment, your current code looks to lead you to a NullPointerException since you're trying to call a method on a field that never appears to have been initialized. I'm OK with your using an inner class for simple listener interfaces, and as noted, an anonymous inner class would work fine, but you must do this with care. If you need to refer to an outer class variable you have a few options:
If the outer variable is a field rather than a local variable, the inner class can directly reference it.
If it is a local variable, it must be declared final.
Most Swing listeners have an XxxEvent parameter that returns the source of the event via getSource() and this can often lead you to a non-inner class reference.
For example
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class Foo2 extends JPanel {
private static final Color NEW_COLOR = new Color(112,253,95);
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private JMenuBar menuBar = new JMenuBar();
public Foo2() {
JMenuItem chameleon = new JMenuItem(new ChangeColorAction("Change Color"));
JMenu menu = new JMenu("Menu");
menu.add(chameleon);
menuBar.add(menu);
}
public JMenuBar getMenuBar() {
return menuBar;
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class ChangeColorAction extends AbstractAction {
public ChangeColorAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
setBackground(NEW_COLOR);
}
}
private static void createAndShowGui() {
Foo2 mainPanel = new Foo2();
JFrame frame = new JFrame("Foo2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setJMenuBar(mainPanel.getMenuBar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
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.
I have 2 classes. Both implements runnable to create the GUI. The first one is the main, and the second one is the secondary class.
I want within the actionlistener of the main class to startup the secondary class.
Here is the code (the two classes are separated files):
public class Main implements Runnable
{
private JTextField txt1, txt2;
private JLabel lbl1, lbl2;
public void run()
{
JFrame frame = new JFrame("Secondary");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
JPanel background = new JPanel();
background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));
.........
// Horizontally adding the textbox and button in a Box
Box box = new Box(BoxLayout.Y_AXIS);
......
background.add(box);
pane.add(background);
frame.pack();
frame.setVisible(true);
}
private class SListener implements ActionListener
{
public void actionPerformed(ActionEvent a)
{
Secondary s = new Secondary();
}
}
public static void main (String[] args)
{
Main gui = new Main();
SwingUtilities.invokeLater(gui);
}
}
public class Secondary implements Runnable
{
private JTextField txt1, txt2;
private JLabel lbl1, lbl2;
public Secondary()
{
Secondary gui = new Secondary();
SwingUtilities.invokeLater(gui);
}
public void run()
{
JFrame frame = new JFrame("Secondary");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
JPanel background = new JPanel();
background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));
.........
// Horizontally adding the textbox and button in a Box
Box box = new Box(BoxLayout.Y_AXIS);
......
background.add(box);
pane.add(background);
frame.pack();
frame.setVisible(true);
}
}
I want to keep the code in two files, I don't want to mixed the two classes in one file.
As you can see from the code, in the Secondary class, in it's constructor I create an Instance of the Secondary class and I run the gui so that when the Instance of this class is created in the Main class, to run the gui.
Unfortunately this technique is not working.
Any ideas?
Thanks
The following line are complety wrong:
public Secondary(){
Secondary gui = new Secondary();
SwingUtilities.invokeLater(gui);
}
Each time you call new Secondary() somewhere in your code, the above code will be triggered, which in turn calls new Secondary() again, and again, and again, ... and your program is blocked.
You probably want to replace it either by
public Secondary(){
SwingUtilities.invokeLater(this);
}
which will avoid the loop, but this is weird behaviour for a constructor.
It makes much more sense to switch to an empty constructor (or delete it all together)
public Secondary(){
}
and rewrite your listener to
public void actionPerformed(ActionEvent a){
Secondary s = new Secondary();
SwingUtilities.invokeLater( s );
}
I would recommend that you completely re-design your program. I find that it is most helpful to gear my GUI's towards creation of JPanels, not top level windows such as JFrame, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. I find that this greatly increase the flexibility of my GUI coding, and is exactly what I suggest that you do. So...
Your first class creates a JPanel that is then placed into a JFrame.
In the first class's ActionListener, create an instance of the 2nd class, place it into a JDialog (not a JFrame), and then display it.
For example,
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TwoWindowEg {
public TwoWindowEg() {
// TODO Auto-generated constructor stub
}
private static void createAndShowGui() {
GuiPanel1 mainPanel = new GuiPanel1();
JFrame frame = new JFrame("Main GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class GuiPanel1 extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private GuiPanel2 guiPanel2 = new GuiPanel2(); // our second class!
private JDialog dialog = null; // our JDialog
public GuiPanel1() {
setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
add(new JButton(new LaunchNewWindowAction("Launch New Window")));
add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class LaunchNewWindowAction extends AbstractAction {
public LaunchNewWindowAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
if (dialog == null) {
// get the Window that holds this JPanel
Window win = SwingUtilities.getWindowAncestor(GuiPanel1.this);
dialog = new JDialog(win, "Second Window", ModalityType.APPLICATION_MODAL);
dialog.add(guiPanel2);
dialog.pack();
}
dialog.setVisible(true);
}
}
}
class GuiPanel2 extends JPanel {
public GuiPanel2() {
setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
add(new JLabel("The second JPanel/Class"));
add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
}
}
class DisposeAction extends AbstractAction {
public DisposeAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Component comp = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(comp);
win.dispose();
}
}
Alternatively, you could swap JPanel "views" using a CardLayout, but either way, you will want to avoid showing two JFrames. Please have a look at The Use of Multiple JFrames, Good/Bad Practice?.
Here is my class:
public class ButtonPanel extends JPanel {
public ButtonPanel () {
makeButton ("button1");
makeButton ("button2");
makeButton ("button3");
}
void makeButton (String name) {
JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setText("I was clicked");
}
});
}
}
When the button is clicked, its text should change to "I was clicked". However, I don't know how to access the setText method. I tried button.setText("I was clicked") but this is not possible.
By making the reference of JButton as final, like :
void makeButton(String name)
{
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
button.setText("I was clicked");
}
});
}
Here is one related example :
Add action to a Button created by another Button
EDIT 1:
Here is one updated version of your code, that works as mentioned before :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonExample1 extends JPanel {
private JButton makeButton (String name) {
final JButton button =new JButton(name);
add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
button.setText("I was clicked");
}
});
return button;
}
private void displayGUI() {
JFrame frame = new JFrame("Button Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.add(makeButton("One"));
contentPane.add(makeButton("Two"));
contentPane.add(makeButton("Three"));
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
new ButtonExample1().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
EDIT 2 :
Here is the answer that tries to explain a reason, why you need to declare it as final
To answer your question, you need to understand the basics, as to how the JVM use to work.
When the classes are compiled which contain inner classes, the byte code which gets generated does not actually implement inner classes as a class within a class.
WHY THE ERROR : The local variable was accessed from an inner class, needs to declare it final
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
public foo()
{
final JMenu edit = new JMenu();
edit.getItem(0).addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
When you compile your this program, two files will be created, Foo.class and Foo$1.class. So now your problem comes, since the Second class i.e. foo$1.class doesn't know that Variable edit is present inside the First class i.e. foo.class.
So how to solve this problem ? What JVM does, is that, It makes a requirement for the developer to make the variable of an outer class to be declared as final.
Now this being done, now JVM quietly places a hidden variable with the name val$edit inside the 2nd compiled class file, here is the output as got from javap
Ouput for foo.class
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
public foo();
}
Now since, edit is local to the constructor, hence the output as above.
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final javax.swing.JMenu val$edit;
final foo this$0;
foo$1(foo, javax.swing.JMenu);
public void mouseClicked(java.awt.event.MouseEvent);
}
The Variable val$edit is assigned the same value which has been assigned to edit since now the compiler knows that the value cannot be changed as it has been declared final and hence it works this time.
Now what if I change the edit Variable from being Local to being Instance. Now the object of the class knows everything about this variable edit, if it gets changed. So changing the above program likewise we get :
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JMenu;
import javax.swing.JPanel;
public class foo extends JPanel
{
JMenu edit = new JMenu();
public foo()
{
edit.getItem(0).addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount() == 1) {
edit.getItem(0).setEnabled(true);
}
}
});
}
}
Here in this case, we are not suppose to declare and define it as being final, because in this case since the Variable being Local to the whole class, the Variable is send to the Inner Class along with the Object Reference i.e. this
C:\Mine\JAVA\J2SE\folder>javap foo.class
Compiled from "foo.java"
public class foo extends javax.swing.JPanel {
javax.swing.JMenu edit;
public foo();
}
Here is how the Variable is send in this case i.e. this$0 :
C:\Mine\JAVA\J2SE\folder>javap foo$1.class
Compiled from "foo.java"
class foo$1 extends java.awt.event.MouseAdapter {
final foo this$0;
foo$1(foo);
public void mouseClicked(java.awt.event.MouseEvent);
}
Seems like that the interpretation, how this situation works, according to me.
Just now I found this wonderful explanation on the internet regarding Mystery of Accessibility in Local Inner Classes, might be this will help you understand the situation in a much better way :-)
Ok so I'm working on an Eclipse plugin based on the JGraph example. The problem is I can't really get the "save" method to work, here's how the program works in short:
- I have a DiagramEditor class with an init() method, where I create a GraphEditor object and call the createFrame() methord of that object.
- GraphEditor extends the BasicGraphEditor (which extends JPanel), the createFrame() method returns a JFrame and has a line "frame.setJMenuBar(menuBar)"
- the "menuBar" is an object variable, which is initialized in the BasicGraphEditor.
Till here everything is cool, the problem is with the action listener which is supposed to save a file. To get the graph I need to get the GraphEditor component, so I do a Component component = (Component) e.getSource() whitch is the ActionEvent passed to that action listener and at that stage is the JMenuItem "save", then I get the parent which is the JPopupMenu, then I want to get that JPopupMenu's parent which should be the GraphEdiotor, but instead I get a null. Any idea why?
Here's some source code:
DiagramEditor.java:
#Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
setSite(site);
setInput(input);
this.diagram = ((DiagramEditorInput)input).getDiagram();
setPartName(this.diagram.getName());
gEditor = new GraphEditor();
gEditor.createFrame().setVisible(true);
}
BasicGraphEditor.java:
public JFrame createFrame()
{
JFrame frame = new JFrame();
frame.getContentPane().add(this);
frame.setJMenuBar(menuBar);
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(870, 640);
return frame;
}
In the constructor:
menuBar = new JMenuBar();
menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menuBar.add(menu);
JMenuItem openMenuItem = new JMenuItem("Open", KeyEvent.VK_O);
// ADD FILE OPENING
//openMenuItem.addActionListener(menuListener);
menu.add(openMenuItem);
JMenuItem saveMenuItem = new JMenuItem("Save", new ImageIcon("/images/save.gif"));
saveMenuItem.setMnemonic(KeyEvent.VK_S);
saveMenuItem.addActionListener( new SaveAction(false) );
menu.add(saveMenuItem);
// menu.add(new SaveAction(false));
JMenuItem saveMenuItemAs = new JMenuItem("SaveAs", new ImageIcon("/images/saveas.gif"));
//saveMenuItemAs.setMnemonic(KeyEvent.VK_S);
saveMenuItemAs.addActionListener( new SaveAction(true) );
menu.add(saveMenuItemAs);
//menu.add(new SaveAction(true));
JMenuItem closeMenuItem = new JMenuItem("Close", KeyEvent.VK_C);
closeMenuItem.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
menu.add(closeMenuItem);
The menu is attached to the frame not your class. Probably the best option is to make sure your SaveAction can see what it needs directly. When you construct your SaveAction, it can have an implicit or direct reference to the GraphEditor.
If you define your SaveAction class INSIDE the GraphEdtior class like this:
class SaveAction extends AbstractAction
{
public void actionPerformed(ActionEvent e) {
GraphEditor myGE = GraphEditor.this;
.. do whatever
}
}
You'll see your SaveAction already has access to the GraphEditor (an implicit reference).
If your SaveAction class is defined as static, or defined in a different class or file, then you simply need to give it the GraphEditor when you construct it and make it hold the reference:
class SaveAction extends AbstractAction
{
private GraphEditor graphEditor;
private boolean myBoolean;
public SaveAction(GraphEditor graphEditor, boolean myBoolean)
{
this.myBoolean = myBoolean;
this.graphEditor = graphEditor;
}
public void actionPerformed(ActionEvent e) {
this.graphEditor....
.. do whatever
}
}
In Both cases, your actionPerformed() in your saveAction will have access to the GraphEditor to do what you require.
Basically what I want to do is get a start button to initiate a method running in another class and acting on another object.
My code for the listener:
button1a.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent event) {
// Figure out how to make this work
//sim.runCastleCrash();
}
} );
My code for the other class:
public static void main(String[] args) {
CastleCrash sim;
sim = new CastleCrash();
}
and
public void runCastleCrash() {
System.out.println("Castle Crash is beginning...");
//Other method parts here to be added
}
I get the feeling this can't be too hard, but I'm missing a piece.
One way to reference things in an anonymous class is using the final keyword:
public static void main(String[] args) {
final Object thingIWantToUse = "Hello";
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
System.out.println(thingIWantToUse);
}
});
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
Alternatively, you can access members (variables or methods) of an enclosing type:
public class ActionListenerDemo2 {
private final JFrame frame = new JFrame();
private Object thingIWantToUse = "Hello";
public ActionListenerDemo2() {
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
thingIWantToUse = "Goodbye";
System.out.println(thingIWantToUse);
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new ActionListenerDemo2().frame.setVisible(true);
}
}
I've had the same problem like you and this is how i solved it.
You can either make your object final (final CastleCrash sim = new CastleCrash();), but i didn't want to do that, or you can make something like a setter method to run the method in your other class:
My code for the listener class:
button1a.addActionListener(new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
//How to make this work ?
//Like this:
runCC();
}
});
public void runCC()
{
CastleCrash sim = new CastleCrash();
sim.runCastleCrash();
}
My code for the other class:
public void runCastleCrash()
{
System.out.println("Castle Crash is beginning...");
//Other method parts here to be added
}
Hope this is helpful, good luck ! :)
McDowell already answers practically with good examples on how to access variables from event listeners (or anonymous inner classes in general). There is however a more general Sun resource on Event Listeners in Swing that is canonical and a good overview of all the caveats to take into account when writing them.
Somehow you need a reference to your CastleCrash object available to call from your actionListener.
You probably want to subclass JFrame, or whatever is containing your JButton such that it has your both your main method and a CastleCrash property that can then be referenced from your anonymous inner class Actionlistener.
BUT - be careful, you look like you are calling what will be a long running method from within the GUI event thread (where the action listener will called). This is generally a bad idea, you will case your GUI to become unresponsive.
See http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html especially the bit on SwingWorker class for ideas on how to avoid that problem.