I'm trying to write a Tic Tac Toe program using swing, but I seem to having some trouble. In my anonymous inner classes I attempt to set up the actionListener for each of my buttons, but I'm having trouble finding the type or the variable which will allow me to reference the buttons and set them to either X or Y. I tried e.getSource().setText() in my anonymous classes, but that came back with errors. Any thoughts?
Thanks!
Alex
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TicTacToe {
public JFrame frame;
public JLabel label;
public JPanel panel;
public static int counter;
public void go()
{
frame = new JFrame("TicTacToe");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new GridLayout(3,3,10,10));
frame.add(BorderLayout.CENTER, panel);
label= new JLabel("TIC TAC TOE");
frame.add(BorderLayout.NORTH, label);
;
JButton button1 = new JButton("Button 1");
JButton button2 = new JButton("Button 1");
JButton button3 = new JButton("Button 1");
JButton button4 = new JButton("Button 1");
JButton button5 = new JButton("Button 1");
JButton button6 = new JButton("Button 1");
JButton button7 = new JButton("Button 1");
JButton button8 = new JButton("Button 1");
JButton button9 = new JButton("Button 1");
button1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button4.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button5.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button6.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button7.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button8.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
button9.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
}
});
panel.add(button1);
panel.add(button2);
panel.add(button3);
panel.add(button4);
panel.add(button5);
panel.add(button6);
panel.add(button7);
panel.add(button8);
panel.add(button9);
frame.setVisible(true);
panel.setVisible(true);
}
public static void main(String[] args)
{
TicTacToe gui = new TicTacToe();
gui.go();
}
}
Remember, ActionListener can be used on a number of different types of components, so the source reference is generalized. You need to cast to back to the expected value
button9.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
if (source instanceof JButton) {
JButton btn = (JButton)source;
// Go ahead and do what you like
}
}
});
While I know your ActionListener as it stands can pretty much guarantee that the source type of the Object will be a JButton, I never like blindly casting objects, but that's me
If you are receiving errors then you should post them but I am assuming it is because you aren't asserting that the source object is in fact a button. There are two straightforward solutions to what you are doing.
First is that since you are only adding one action listener to each button, you can assume that it is the object that the action event is referring to. Just note that the button either needs to be an instance variable or declared final:
button1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e)
{
button1.setText("X/Y");
}
});
Second, which would fix the cause of your error, is by asserting that the ActionEvent source object is in fact a button. This is done by checking that the source is an instance of JButton:
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
((JButton) e.getSource()).setText("X/Y");
}
}
});
I went through and cleaned up your code a little bit. I'm not quite sure why your code had errors, but I didn't get any. I suggest, since you have common code, to reuse it like I did in an array. I also added a boolean to switch between players on each button click.
Lastly, I suggest setting up the JFrame in the constructor, or in a private method called by the constructor (more complex user interfaces might have a lot of code, and breaking it up is a good habit for maintainability of your code) like I showed below.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TicTacToe {
public static final boolean PLAYER_X = false;
public static final boolean PLAYER_O = true;
public static int counter;
private JFrame frame;
private JLabel label;
private JPanel panel;
private JButton[] buttons;
private boolean player;
public TicTacToe() {
frame = new JFrame("TicTacToe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setPreferredSize(new Dimension(500, 500));
panel.setLayout(new GridLayout(3, 3, 10, 10));
frame.add(BorderLayout.CENTER, panel);
label = new JLabel("TIC TAC TOE");
frame.add(BorderLayout.NORTH, label);
/* Set the initial player turn to player X */
player = PLAYER_X;
/* Create the JButtons */
buttons = new JButton[9];
/* Loop through and set all of them up */
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
buttons[i].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() instanceof JButton) {
((JButton)e.getSource()).setText(player ? "O" : "X"); /* Set button text */
player = !player; /* Switch turns */
}
}
});
/* Add all of the buttons to the panel. */
panel.add(buttons[i]);
}
/* Pack the frame to the contents. Basically a "fit to contents". */
frame.pack();
}
public void go() {
frame.setVisible(true);
panel.setVisible(true);
}
public static void main(String[] args) {
TicTacToe gui = new TicTacToe();
gui.go();
}
}
Related
I'm coding something to work on a game and I've been having trouble trying to make a button set the variable "weapon".
import static java.lang.System.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class UntitledProject {
private JFrame mainFrame;
private JLabel headerLabel;
private JLabel statusLabel;
private JPanel controlPanel;
public UntitledProject() {
prepareGUI();
}
public static void main(String[] args) {
UntitledProject prepare = new UntitledProject();
String weapon = prepare.weapon();
}
private void prepareGUI() {
mainFrame = new JFrame("Untitled Project");
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(3, 1));
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent) {
exit(0);
}
});
headerLabel = new JLabel("", JLabel.CENTER);
statusLabel = new JLabel("", JLabel.CENTER);
statusLabel.setSize(350, 100);
controlPanel = new JPanel();
controlPanel.setLayout(new FlowLayout());
mainFrame.add(headerLabel);
mainFrame.add(controlPanel);
mainFrame.add(statusLabel);
mainFrame.setVisible(true);
}
public String weapon() {
headerLabel.setText("Pick Weapon");
JButton button1 = new JButton("Sword");
JButton button2 = new JButton("Lance");
JButton button3 = new JButton("Axe");
JButton submitButton = new JButton("Submit");
String weapon = "";
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Sword selected.");
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
weapon = "Sword";
exit(0);
}
});
}
});
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Lance selected.");
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
weapon = "Lance";
exit(0);
}
});
}
});
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Axe selected.");
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
weapon = "Axe";
exit(0);
}
});
}
});
controlPanel.add(button1);
controlPanel.add(button2);
controlPanel.add(button3);
controlPanel.add(submitButton);
mainFrame.setVisible(true);
}
I need for when the submit button is pressed the weapon variable is changed to what button was pressed before the submit button.
Make an instance variable.
private JPanel controlPanel; // under this line
private String weapon;
Then everywhere else, remove String in front of weapon because this makes a new, local variable.
Then, you can remove this line
String weapon = "";
To set the sword, for example, use UntitledProject.this.weapon to explicitly set the instance variable.
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Sword selected.");
UntitledProject.this.weapon = "sword";
Do the same for the other buttons.
Then, additionally, the submit button only needs it's action to be set once, not everytime you set a weapon.
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Axe selected.");
UntitledProject.this.weapon = "Axe";
}
});
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
exit(0);
}
});
And, does this app only pick one weapon, then exit?
exit(0);
This tells your whole app to quit with a 0 (success) code, not just close the current window
And since weapon is moved to an instance variable, you can change this to a void method (you weren't returning anything anyways)... Change
public String weapon() {
To
public void weapon() {
You will need to create a temp weapon variable to record the previously selected choice. Once a user selects a weapon update the weapon varible and the temp. Once submit is clicked assign temp to weapon variable and visa versa
By now, I already know my code is flawed. I just want to know why it's flawed. I want to activate the "webButton" so that when it gets clicked, it prints a message on the console that reads "This opens Mozilla Firefox."
package smartphone;
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
import java.util.Scanner;
public class Smartphone implements ActionListener {
public static void main(String[] args) {
{
{
JFrame container = new JFrame();
container.setLayout(new BorderLayout());
Scanner daniel = new Scanner(System.in);
JButton webButton = new JButton(new ImageIcon("Firefox.png"));
JButton phoButton = new JButton(new ImageIcon("Facebook.png"));
JButton texButton = new JButton(new ImageIcon("Phone.png"));
JButton setButton = new JButton(new ImageIcon("Settings.png"));
JButton smsButton = new JButton(new ImageIcon("sms.png"));
container.setTitle("Smartphone Interface!");
container.setSize(240,340);
container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container.add(setButton, BorderLayout.CENTER);
container.add(webButton, BorderLayout.SOUTH);
container.add(texButton, BorderLayout.NORTH);
container.add(phoButton, BorderLayout.EAST);
container.add(smsButton, BorderLayout.WEST);
container.setVisible(true);
webButton.addActionListener(instanceofSmartphone);
}
}
}
}
Do this.
webButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
}
});
If you want to use the ActionListener interface then, implement it in your Frame class and then replace that instanceOfSmartphone with
webButton.addActionListener(this);
And put this outside the method
public void actionPerformed(ActionEvent e) {
if(e.getSource() == webButton) {
}
}
You need to implement the actionPerformed method. An example follows.
public void actionPerformed(ActionEvent e) {
System.out.println("This method opens Mozilla Firefox.");
}
Additionally, you need to change how you add the action listener to the following.
webButton.addActionListener(this);
There are also a number of other issues. Here is a modified version of your code to get it working but far from perfect or what you will want in the end. I strongly recommend you walk through all of the tutorials in order at the below website. It doesn't get any easier than what they have. Also, if your not already using it, you should try Netbeans or some other IDE. It give you feedback that may help while you are starting out.
https://docs.oracle.com/javase/tutorial/
package smartphone;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.util.Scanner;
public class Smartphone extends Frame implements ActionListener {
static JButton webButton = new JButton(new ImageIcon("Firefox.png"));
static JButton phoButton = new JButton(new ImageIcon("Facebook.png"));
static JButton texButton = new JButton(new ImageIcon("Phone.png"));
static JButton setButton = new JButton(new ImageIcon("Settings.png"));
static JButton smsButton = new JButton(new ImageIcon("sms.png"));
Smartphone(){
webButton.addActionListener(this);
}
public static void main(String[] args) {
Smartphone container = new Smartphone();
container.setLayout(new BorderLayout());
Scanner daniel = new Scanner(System.in);
container.setTitle("Smartphone Interface!");
container.setSize(240, 340);
container.add(setButton, BorderLayout.CENTER);
container.add(webButton, BorderLayout.SOUTH);
container.add(texButton, BorderLayout.NORTH);
container.add(phoButton, BorderLayout.EAST);
container.add(smsButton, BorderLayout.WEST);
container.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("This opens a Firefox Webbrowser.");
}
}
You need to add an ActionListener to the buttons INSIDE of the constructor: buttonName.addActionListener(this);.
Then you need to create the following method:
public void actionPerformed(ActionEvent event) {
Object control = event.getSource();
if (control == buttonName) {
//Run code...
}
}
I have created custom button class which extends JComponent and want to add KeyListener on mouseEntered event (and later remove on mouseExited). So my goal is - when the mouse enters this JComponent - then if I press Enter - some code will be executed, related to only this button. How can I do that?
Use Key Bindings instead of KeyListeners, since the latter is way to low level for Swing. Just bring your mouse over the JButton, and then press ENTER, then take your mouse outside the bounds of the JButton and try pressing ENTER again. Have a look at this example and see if this is what you wanted :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ButtonBinding {
private JPanel contentPane;
private JTextField tField;
private JButton button;
private KeyStroke keyStroke = KeyStroke.getKeyStroke("ENTER");
private Action action = new AbstractAction() {
#Override
public void actionPerformed(ActionEvent ae) {
System.out.println("Action Performed");
contentPane.setBackground(Color.BLUE);
}
};
private MouseAdapter mouseActions = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent me) {
System.out.println("Mouse Entered");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "enter");
button.getActionMap().put("enter", action);
}
#Override
public void mouseExited(MouseEvent me) {
System.out.println("Mouse Exited");
JButton button = (JButton) me.getSource();
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, "none");
contentPane.setBackground(Color.RED);
}
};
private void displayGUI() {
JFrame frame = new JFrame("Button Binding Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
contentPane = new JPanel();
contentPane.setOpaque(true);
tField = new JTextField(10);
button = new JButton("Click Me");
button.addMouseListener(mouseActions);
contentPane.add(tField);
contentPane.add(button);
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 ButtonBinding().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
I have a JPanel in a JFrame that contains 5 buttons. In another JPanel there is a button called "delete button", what I want to do is to click this button and than choose what button of the other 5 to delete by ckicking in one of them. Can anyone help me?
public class gui extends JFrame implements ActionListener
{
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
JPanel p2 = new JPanel();
JButton b1 = new JButton("Delete");
JButton b2 = new JButton("A");
JButton b3 = new JButton("B");
JButton b4 = new JButton("C");
gui()
{
p1.setLayout(new GridLayout(1,2));
p1.add(p2);
p1.add(p3);
p2.setLayout(new GridLayout(3,1));
p2.add(b2);
p2.add(b3);
p2.add(b4);
p3.add(b1);
b1.addActionListener(this);
b2.addActionListener(this);
b3.addActionListener(this);
b4.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == b1)
// When I click this button I want to be able to delete a button of my choice (one of the other 3)
}
}
Use a chain of responsibility in the button listeners. One Button listener that listens for the "to be deleted" buttons and the "delete" button. Under normal operation this button listener just sends the "to be deleted" button events to the existing button events, but when it hears a "delete" button event, it then captures the "next" button event without sending it to the existing button listener, and acts to remove the button.
Ok you provided some code. Here is a solution that uses a chain of responsibility. Basically, if one ActionListener can't handle the event, it sends it to the next one, and so on.
import java.awt.GridLayou;
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.WindowConstants;
public class Gui extends JFrame {
public static final long serialVersionUID = 1L;
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
JPanel p3 = new JPanel();
JButton b1 = new JButton("Delete");
JButton b2 = new JButton("A");
JButton b3 = new JButton("B");
JButton b4 = new JButton("C");
public Gui() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
p1.setLayout(new GridLayout(1, 2));
p1.add(p2);
p2.add(p3);
p2.setLayout(new GridLayout(3, 1));
p2.add(b2);
p2.add(b3);
p2.add(b4);
p3.add(b1);
DoItListener doIt = new DoItListener(null);
DeleteItListener deleteIt = new DeleteItListener(this, doIt);
b1.addActionListener(deleteIt);
b2.addActionListener(deleteIt);
b3.addActionListener(deleteIt);
b4.addActionListener(deleteIt);
add(p1);
pack();
}
public void deleteButton(String name) {
if (b2 != null && "A".equals(name)) {
p2.remove(b2);
b2 = null;
p2.invalidate();
p2.redraw();
}
if (b3 != null && "B".equals(name)) {
p2.remove(b3);
b3 = null;
p2.invalidate();
p2.redraw();
}
if (b4 != null && "A".equals(name)) {
p2.remove(b4);
b4 = null;
p2.invalidate();
p2.redraw();
}
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Gui().setVisible(true);
}
});
}
}
class DoItListener implements ActionListener {
private ActionListener delegate;
public DoItListener(ActionListener next) {
delegate = next;
}
public void actionPerformed(ActionEvent e) {
if (!("Delete".equals(e.getActionCommand()))) {
System.out.println("doing " + e.getActionCommand());
} else if (delegate != null) {
delegate.actionPerformed(e);
}
}
}
class DeleteItListener implements ActionListener {
private Gui gui;
private boolean deleteNext;
private ActionListener delegate;
public DeleteItListener(Gui container, ActionListener next) {
gui = container;
delegate = next;
deleteNext = false;
}
public void actionPerformed(ActionEvent e) {
if ("Delete".equals(e.getActionCommand())) {
deleteNext = true;
} else if (deleteNext) {
gui.deleteButton(e.getActionCommand());
deleteNext = false;
} else if (delegate != null) {
delegate.actionPerformed(e);
}
}
}
Here try this code out :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DeleteButtonExample extends JFrame
{
private boolean deleteNow = false;
private JButton deleteButton;
private JPanel leftPanel;
private JPanel rightPanel;
private JButton[] buttons = new JButton[5];
private ActionListener deleteAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JButton button = (JButton) ae.getSource();
if (deleteNow)
{
leftPanel.remove(button);
leftPanel.revalidate();
leftPanel.repaint();
deleteNow = false;
}
else
{
// Do your normal Event Handling here.
System.out.println("My COMMAND IS : " + button.getActionCommand());
}
}
};
private void createAndDisplayGUI()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
setLayout(new GridLayout(0, 2));
leftPanel = new JPanel();
leftPanel.setLayout(new GridLayout(0, 2));
leftPanel.setBackground(Color.WHITE);
for (int i = 0; i < 5; i++)
{
buttons[i] = new JButton("" + i);
buttons[i].addActionListener(deleteAction);
buttons[i].setActionCommand("" + i);
leftPanel.add(buttons[i]);
}
rightPanel = new JPanel();
rightPanel.setBackground(Color.BLUE);
JButton deleteButton = new JButton("DELETE");
deleteButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JOptionPane.showMessageDialog(null, "Delete any Button from the Left Panel by clicking it."
, "INFO : ", JOptionPane.INFORMATION_MESSAGE);
deleteNow = true;
}
});
rightPanel.add(deleteButton);
add(leftPanel);
add(rightPanel);
pack();
setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new DeleteButtonExample().createAndDisplayGUI();
}
});
}
}
OUTPUT :
, ,
Here's a snippet of code to kick you off in the right direction:
import java.awt.event.ActionEvent;
import javax.swing.*;
public class FrameTestBase extends JFrame {
public static void main(String args[]) {
FrameTestBase t = new FrameTestBase();
final JPanel p = new JPanel();
final JButton button = new JButton();
button.setAction(new AbstractAction("Remove me!") {
#Override
public void actionPerformed(ActionEvent e) {
p.remove(button);
p.revalidate();
p.repaint();
}
});
p.add(button);
t.setContentPane(p);
t.setDefaultCloseOperation(EXIT_ON_CLOSE);
t.setSize(400, 400);
t.setVisible(true);
}
}
Before click:
After click:
From the comments:
To generalize this, you could create an AbstractAction that takes the to-be-deleted button as argument. Use this AbstractAction, and update it as necessary whenever your delete-policy should change.
Have a look at the glass pane. This tutorial shows how it is used.
At a high level, clicking the 'Delete' button would put the glass pane listener into a state where it:
detects a click,
determines the target component,
determines whether the component is allowed to be deleted
and if so, delete the component.
As a design note, I would keep a Set of controls that are allowed to be deleted, and thereby separate the concerns. So when you add a button that is allowed to be deleted, it is your responsibility to also add it to the delete candidates set.
The easiest method:
Add an ActionListener to the button that will remove another one;
Repaint and revalidate the panel where is the button to remove.
Example (in this case the button that will delete another one is called by "deleteBtn" and the button in the another panel that will be removed is called by "btnToDlt" that exists in the "panel"):
deleteBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
panel.remove(btnToDlt);
panel.revalidate();
panel.repaint();
}
});
I am attempting a very simple form designed to take user input into a JTextField and show that same input via a pop up dialog.
I can hardcode the JTextField to have a preset number using setText(). If I do this, my program works flawlessly.
However, when I leave the field blank and try getText() to show the text in the pop up dialog, I either get an empty pop up frame, or I get an 'empty string' exception (I am attempting to parse String to Double.)
package buttontest;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import javax.swing.*;
import java.awt.event.ActionEvent;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class ButtonTest
{
public static void main(String[] args)
{
ButtonFrame frame = new ButtonFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
#SuppressWarnings("LeakingThisInConstructor")
public ButtonFrame()
{
setTitle("SunStream Loan Calculator v2.0");
setSize(900,900);
ButtonPanel panel = new ButtonPanel();
panel.add(new JLabel("Enter your loan amount:"));
loanAmt = new JTextField(40);
panel.add(loanAmt);
add(panel,BorderLayout.CENTER);
}
public JTextField loanAmt;
class ButtonPanel extends JPanel implements ActionListener
{
private Component frame;
public ButtonPanel()
{
final JButton b2 = new JButton("Calculate");
add(b2, BorderLayout.SOUTH);
b2.setActionCommand("calculate");
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
ButtonFrame bf = new ButtonFrame();
if("calculate".equals(e.getActionCommand()))
{
JOptionPane.showMessageDialog(frame, bf.loanAmt.getText());
}
}
});
}
#Override
public void actionPerformed(ActionEvent ae) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
Any help would be greatly appreciated. I am researching using a KeyListener or KeyEvent but I don't quite understand it well enough.
You're creating a "shadow" ButtonFrame variable inside of the b2's ActionListener. Yes the bf variable refers to a ButtonFrame object which is of the same class as the displayed ButtonFrame object, but it refers to a completely distinct and non-visualized object. The key to a solution is to get the text from the ButtonFrame object that is actually displayed, and this can be obtained from within an inner class via the ButtonFrame.this construct:
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//!! ButtonFrame bf = new ButtonFrame();
if ("calculate".equals(e.getActionCommand())) {
//!! note use of ButtonFrame.this:
JOptionPane.showMessageDialog(frame, ButtonFrame.this.loanAmt.getText());
}
}
});
Next consider using public getters rather than accessing fields such as the JTextField directly. This reduces the chances of the code causing side effects, such as changing the properties of the JTextField object inadvertently.
For instance (changes denoted by //!! comment):
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class ButtonTest {
public static void main(String[] args) {
ButtonFrame frame = new ButtonFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ButtonFrame extends JFrame {
private JTextField loanAmt; // !! Make field private
#SuppressWarnings("LeakingThisInConstructor")
public ButtonFrame() {
setTitle("SunStream Loan Calculator v2.0");
setSize(900, 900);
ButtonPanel panel = new ButtonPanel();
panel.add(new JLabel("Enter your loan amount:"));
loanAmt = new JTextField(40);
panel.add(loanAmt);
add(panel, BorderLayout.CENTER);
}
// !! create a public method to get JTextField's text
// !! without exposing the JTextField itself.
public String getLoanAmtText() {
return loanAmt.getText();
}
class ButtonPanel extends JPanel implements ActionListener {
private Component frame;
public ButtonPanel() {
final JButton b2 = new JButton("Calculate");
add(b2, BorderLayout.SOUTH);
b2.setActionCommand("calculate");
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// !! ButtonFrame bf = new ButtonFrame();
if ("calculate".equals(e.getActionCommand())) {
//!! call public method on ButtonFrame object
JOptionPane.showMessageDialog(frame,
ButtonFrame.this.getLoanAmtText());
}
}
});
}
#Override
public void actionPerformed(ActionEvent ae) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
}
The only way you can access your loanAmt is through ButtonPanel itself. Because you add loanAmt to this button right ?
So, if you want access loanAmt. You must get all component on this button panel. This is my psudeo code howto accessing your loanAmt from ButtonPanel class.
b2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ButtonFrame bf = new ButtonFrame();
if("calculate".equals(e.getActionCommand())) {
// Get all component
java.awt.Component[] componentList = this.getComponents();
JTextField txtField;
String value;
for (int i = 0; i < componentList.length; i++) {
if (componentList[i].getClass().getName().equals("javax.swing.JTextField")) {
txtField = (JTextField) componentList[i];
value = textField.getText();
}
}
if (value != null) JOptionPane.showMessageDialog(frame, value);
}
}
});