I have the following constructor which defines a board and checks if any of the three JButtons have been clicked:
Timer timer = new Timer(500, this);
private boolean[][] board;
private boolean isActive = true;
private int height;
private int width;
private int multiplier = 40;
JButton button1;
JButton button2;
JButton button3;
public Board(boolean[][] board) {
this.board = board;
height = board.length;
width = board[0].length;
setBackground(Color.black);
button1 = new JButton("Stop");
add(button1);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
isActive = !isActive;
button1.setText(isActive ? "Stop" : "Start");
}
});
button2 = new JButton("Random");
add(button2);
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
button3 = new JButton("Clear");
add(button3);
button3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = clearBoard();
}
});
}
But it returns this error:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
board cannot be resolved or is not a field
board cannot be resolved or is not a field
Why is this? How do I access this.board in the constructor?
The problem is caused by you trying to access this.board inside the anonymous inner classes. Since there is no board field defined, that causes an error.
For example this:
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
In order to be able to use the board variable inside your anonymous inner classes you either need to remove this or use something like Board.this.board (if you want to be more explicit).
This should work:
Board.this.board = randomBoard();
The problem is this related to the class ActionListener which did not have a board variable. However with Board.this you specify that you mean the board member of the Board class. This is the syntax you need to use for nested classes to access the variables of the outer class.
The problem is here
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
this.board = randomBoard();
}
});
your button2 is a JButton, and it doesn't have a board field. Don't access it with this.board. Find another way to access board.
The fast and dirty way to do it would be to make board static, but I'm sure that JButton has a way for you to specify a parent(your board class), and access the board field that way.
After a quick look at The documentation for JButton, I've found a getParent method. I'd start with that.
As others and the compiler said, you don't have a field (which is an instance member), but only a local variable board, which goes out of scope as soon as constructor exits.
Related
public static void main(String[] args) {
ControlledBall ball2 = new ControlledBall(12,2);
JFrame window = new JFrame("Controlled Ball");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton stop = new JButton("Stop");
stop.setSize(4,400);
stop.setVisible(true);
stop.setText("Stop");
stop.addActionListener(new Action());
i get an error on the last line that says 'controlledball.this cannot be referenced from a static context'
when i try the following technique instead of calling the stop() method i just change the values i need to change:
stop.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
x= 0;
y = 0;
}
});
i get the error non-static field 'x' cannot be referenced from a static context...
the question is, from the main method how can i change the values of x and y which are declared in another method?
There are may ways you can solve this problem. A good suggestion is to probably create a custom ActionListener that holds a reference to the Object you want to change. For example, you could have:
class StopListener implements ActionListener {
private ControlledBall ball;
public StopListener(ControlledBall ball) {
this.ball = ball;
}
#Override
public void actionPerformed(ActionEvent e) {
ball.stop(); // sets x and y to zero
}
}
Then you can just instantiate and use that class as an ActionListener:
stop.addActionListener(new MyListener(ball2));
This should help you organize your code and keep it clean and maintainable.
I am trying to do something similiar as cookie clicker, nevertheless it does not work. I have not managed to create a "counter" that shows the amount of clicks. This is what I got hitherto, any ideas?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Stocks implements ActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Stocks().createGui();
}
});
}
public void createGui() {
JFrame frame = new JFrame("Clicker");
frame.setSize(175, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
frame.add(panel);
frame.getContentPane().add(panel, BorderLayout.WEST);
GridBagConstraints c = new GridBagConstraints();
JButton button1 = new JButton("Click this");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(40, 40, 40, 40);
panel.add(button1, c);
button1.addActionListener(this);
}
You can have a variable int cnt = 0; inside your Stocks class and everytime someone clicks on the button you increase cnt by one in the actionPerformed method.
As you said, your actionPerformed method is empty, meaning you coded your application to do nothing when the button is clicked.
This answer is assuming you only have one component using that class as ActionListener:
In earlier versions of Java, it would be:
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
Java 8, however, provides us with Lambda expressions, and allows this to be a lot easier (with less code).
button1.addActionListener(event -> counter++);
You don't need to create an implementation of ActionListener, Java 'll take care of this for you. If you write your code like this, it is even easier if you have more components using that class as ActionListener, since you won't be able to mix them up.
If you need them to call shared parts of code, you can still call methods from within the Lambda expression
button1.addActionListener(event -> {callSharedMethod(); counter++;});
In this example, first the shared method will be called. After that, the counter will be augmented, which will/might only be done from clicking this button.
You should first add a counter as a attribute of your class `Stock``
public class Stocks {
private int counter;
Initialize counter variable with 0:
public static void main(String[] args) {
this.counter = 0;
And then add the action listener to increase the variable:
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
});
I'm surprised nobody proposed resolving this by inheritance. The button you want is a JButton but slightly more specialized (it must count the number of clicks performed on itself).
public final class CountButton extends JButton {
private int counter = 0;
public CountButton(String text) {
super(text);
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter++;
}
});
}
public final int getCounter() {
return counter;
}
}
So in my Java Swing application, I need a button ActionListener to be able to access variables outside of its scope like so:
int x = 13;
JButton btn = new JButton("New Button");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(x);
}
});
but I get a variable out of scope error. How can I access it?
The action listener is an anonymous inner class. This means that it can only use final variables from an outer scope. So, either declare x as final or pass it into the class some other way.
This should work:
final int x = 13;
JButton btn = new JButton("New Button");
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(x);
}
});
Alternatively, see Pass variables to ActionListener in Java for some other options.
For example, I am trying to call the setEnable method on a JButton that I constructed within the parameter parenthesis of an add method:
add(new JButton());
I know I could just do something like:
JButton button = new JButton();
button.setEnable(false);
but is there I way I can call setEnable on a JButton that I didn't assign a reference name to?
The reason why I am not assigning the JButton a reference name is because I am supposed to add an unknown number of JButtons to a JPanel. How I am doing this, is by using this for loop.
for (int i = 0; i < numberOfButtonsToAdd; i++)
{
JPanelName.add(new JButton());
}
and I want all the JButtons to be disabled.
You state in comment:
The reason why I am not assigning the JButton a reference name is because I am supposed to add an unknown number of JButtons to a JPanel. How I am doing this, is by using a for loop: for (int i = 0; i < numberOfButtonsToAdd; i++) { JPanelName.add(new JButton()); }
Then just use either an array or ArrayList of JButton.
// in your field declarations
List<JButton> buttonList = new ArrayList<JButton>();
// elsewhere in your program
for (int i = 0; i < numberOfButtonsToAdd; i++) {
JButton button = new JButton();
buttonList.add(button);
somePanel.add(button);
}
Now you have a reference to any button in the list via buttonList.get(someIndex)
Note also, that most buttons are given ActionListeners that are activated whenever the button is pressed. Without such listeners, the buttons are pretty much useless. You can also get a reference to the pressed JButton from the ActionListener via the ActionEvent object passed into its actionPerformed method:
public void actionPerformed(ActionEvent e) {
AbstractButton myButton = (AbstractButton) e.getSource();
// now you can use myButton
}
Note that this is key information that you should have shared with us up front in your original question.
Edit
You state now:
and I want all the JButtons to be disabled.
Then just make them disabled from the get-go:
for (int i = 0; i < numberOfButtonsToAdd; i++) {
JButton button = new JButton();
button.setEnabled(false);
buttonList.add(button);
somePanel.add(button);
}
Although I am curious -- why all disabled? Why no ActionListener? No text?
Edit 2
You state:
Would I still be able to access those individual buttons later on, since they are all assigned "button"?
Please understand that the variable name is of little importance, and in fact, in my example above, the variable named button does not exist outside of the for loop within which it was declared. Instead what matters is the reference to the JButton object. As has been much discussed in the other answers and as you are aware, this can be obtained by using a variable, but it doesn't have to be a variable directly to the JButton, it could, as is in this case, be the variable to the ArrayList<JButton>. That's why I suggest that you create this entity.
Edit 3
for example:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class ButtonLists extends JPanel {
private static final int ROWS = 6;
private static final int COLS = 6;
private List<JButton> allButtons = new ArrayList<JButton>();
private List<JButton> evenButtons = new ArrayList<JButton>();
public ButtonLists() {
JPanel gridPanel = new JPanel(new GridLayout(ROWS, COLS));
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
int buttonInt = i * COLS + j;
String buttonString = String.valueOf(buttonInt);
JButton button = new JButton(buttonString);
button.setEnabled(false);
gridPanel.add(button);
allButtons.add(button);
if (buttonInt % 2 == 0) {
evenButtons.add(button);
}
}
}
JPanel bottomPanel = new JPanel();
bottomPanel.add(new JButton(new AbstractAction("Activate All") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(true);
}
}
}));
bottomPanel.add(new JButton(new AbstractAction("Activate Even") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(false);
}
for (JButton btn : evenButtons) {
btn.setEnabled(true);
}
}
}));
bottomPanel.add(new JButton(new AbstractAction("Activate Odd") {
#Override
public void actionPerformed(ActionEvent e) {
for (JButton btn : allButtons) {
btn.setEnabled(true);
}
for (JButton btn : evenButtons) {
btn.setEnabled(false);
}
}
}));
setLayout(new BorderLayout());
add(gridPanel, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ButtonLists");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ButtonLists());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
If you added it to a panel you can get the components of that panel and looping through those components if one is a button you could call setEnabled(), but if there were more than one button you would have to determine if it was the correct one.
Edit:
Since you added that you want all the buttons disabled then this method should work nicely. Examples:
All:
for(Component c : panel.getComponents()){
c.setEnabled(false);
}
Just JButtons:
for(Component c : panel.getComponents()){
if(c instanceof JButton){
((JButton)c).setEnabled(false);
}
}
No, you can't. If setEnabled() returned the object it's enabling, you could enable-and-add the object in a single line. But as it is, setEnabled() returns void, so you have no choice but to use a local variable.
However, a JButton is enabled by default, so there's no need to explicitly call setEnabled() on it, it's already enabled!
You can call a method in a new instance like
new JButton().setEnabled(true);
But this won't allow you to access the JButton instance you create here anymore and thus you cannot call add().
This can only be possible if the method call returns the instance object on which it was called. So if for example setEnabled would return the same instance on which it was called (that is, this in setEnabled context) , you could do add(new JButton().setEnabled(true)).
Anyway in your case don't be afraid of using references:
final JButton button = new JButton();
button.setEnabled(true);
add(button);
Note that in this case 2 last methods can be called in any order, the result will be the same.
The only way this can work is if what ever you are adding it to has a get method. other than that you don't have any other options. Best way is what you showed.
JButton button = new JButton();
button.setEnable(true);
This seems like a very simple problem, but I'm having a lot of trouble figuring out how to deal with it.
Sample Scenario:
final int number = 0;
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setSize(400, 400);
final JTextArea text = new JTextArea();
frame.add(text, BorderLayout.NORTH);
JButton button = new JButton(number + "");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
number++; // Error is on this line
text.setText(number + "");
}});
frame.add(button, BorderLayout.SOUTH);
I really have no idea where to go.
If you declared number as final, you cannot modified its value. You must remove the final modificator.
Then, you can access to that variable via:
public class Scenario {
private int number;
public Scenario() {
JButton button = new JButton(number + "");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Scenario.this.number++;
text.setText(Scenario.this.number + "");
}
});
}
}
The notation "ClassName.this" allow you to access to the object of a class where you are in.
Keep atention in when you use "number" first time, -new JButton(number)-, you can access to number directly, because you are in Scenario scope. But when you use it inside your ActionListener, you are in your ActionListener scope instead of Scenario scope. That is why you cannot see the variable "number" directly inside of your action listener and you have to access to the instance of Scenario where you are in. This can be done by Scenario.this
The fastest solution would be to declare number as static, and reference it using the name of your class.
Alternatively you can make a class that implements ActionListener, and pass number and text into it's constructor.