I was creating a code having 36 buttons in Jbutton array buttons[].
I added an action listener to each of those using a loop
for (int ghe = 0; ghe < button.length; ghe++) {
button[ghe].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
button[ghe].setVisible(false);
}
});
}
I want the clicked button to be made invisible but every time the netbeans ide gives a syntax error
variable referenced from inner class must be final
What should I do?
As your method is specified, it will not work. ghe is of type int, which does not provide a .setVisible method.
My solution is to save the button from the array into a variable and work with it.
for (int ghe = 0; ghe < button.length; ghe++)
{
JButton currentButton = button[ghe];
currentButton.addActionListener(e -> currentButton.setVisible(false));
}
Related
I am trying to build a GUI application that will let the user to choose product by clicking the button. I hold products in an ArrayList and then use this ArrayList and for loop to create proper number of JButtons. When user clicks the button price of that product should appear in the TextField.
My problem is: how to find out which button was clicked? If I was using Array of Buttons (JButton button[] = new JButton[3]) I would find it in the loop:
if (target.equals(button[i]))...
But I can't figure out how to find it when I use ArrayList of products to create buttons. Any help would be well appreciated. Here's my code (I tried many approaches so I only post the one I started with - it finds only the last item in the ArrayList).
public void addStuff() {
stuffList.add(new Stuff("Lemon Haze", 15.00));
stuffList.add(new Stuff("OG Kush", 16.00));
stuffList.add(new Stuff("Strawberry Cough", 18.00));
for (int i = 0; i < stuffList.size(); i++) {
stuffButton = new JButton();
stuffPanel.add(stuffButton);
stuffButton.setText(stuffList.get(i).getName());
stuffButton.addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
Object target = e.getSource();
for (int i = 0; i < stuffList.size(); i++) {
if (target == stuffButton) {
subtotalTextF.setText(stuffList.get(i).getPrice() + "");
}
}
}
Create a specific class for your ActionListener, and give it a reference to your Stuff - this way you can create a specific instance for each button that automatically links back to the correct instance of Stuff, without trying to search on the fly:
stuffButton.addActionListener(new StuffListener(stuffList.get(i));
...
private class StuffListener implements ActionListener {
private final Stuff myStuff;
public StuffListener(Stuff stuff) {
this.myStuff = stuff;
}
public void actionPerformed(ActionEvent e) {
subtotalTextF.setText(String.valueOf(myStuff.getPrice()));
}
}
Note that you can accomplish this with a bit less code using lambdas, but figured this is the clearest way to explain the logic, which is the same either way.
On a side note, based on the code you've posted, the reason it's only getting the last button is because you're comparing to stuffButton, which is not changed from the last instance after your initialization loop is done.
I see there are some questions already asked about this topic but I haven't come up to an answer for my. I am writing a code where user types something in JTextField, and after clicking a button, his word is replaced with the number of asterisks with the same number of characters his word had e.g "table" would be replaced by "****". i did it this way:
ask.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String guess = "";
String given = textGive.getText();
for (int i=0; i<given.length(); i++){
String asterisk = "*";
guess += asterisk;
textGive.setText(guess);
}
}
});
I know that I did not do this in a great way, but I did not know how to do it better. Any recommendations?
Now, I want somehow to save both Strings, the original word and the asterisk one outside the scope so I can access it in another ActionListener and modify it further.
Before writing first ActionListener i did write String guess = "" and String given = "" but it seems as it did not do anything.
So, in my second ActionListener i want to send him the string given I received when the user typed his word.
guess.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String attempt = textGuess.getText();
char att = attempt.charAt(0);
for (int i=0; i<5; i++){
if (given.charAt(i)==att){
textGuess.setText("Ok!");
}
}
}
});
Eclipse gives me error saying:
"Cannot refer to the non-final local variable given defined in an enclosing scope".
I understand that I need to make given final in order to acces it further, but how to do that if the variable depends on text input from first ActionListener? Is there some other solution for this problem? I've recently started using java, so I do not know the language so well.
Anything that you want visible to class should be placed in instance fields, not in local variables. For instance, the given variable should be a private non-static field declared in the class, and not a variable buried within your listener's actionPerformed method.
e.g.,
public class Foo extends JPanel {
private JButton ask = new JButton("Ask");
private JTextField textGive = new JTextField(10);
private String given = ""; // visible throughout the class
public Foo() {
add(textGive);
add(ask);
ActionListener listener = e -> {
String guess = "";
// String given = textGive.getText(); //visible only within this method
given = textGive.getText();
guess = given.replaceAll("\\w", "*");
textGive.setText(guess);
};
ask.addActionListener(listener);
textGive.addActionListener(listener); // also give the same listener to the JTextField
}
private int var = 0;
test(){
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
String selection = (String) items.getSelectedItem();
for (int i = 0; i < itms.length; i++) {
if (selection == itms[i]) {
var = 10 + i;
System.out.println(var); // prints the desired value
}
}
}
};
System.out.println(var); // prints 0 but why not desired value???
}
This actionListener is for a combo box. I want to take the value of the selected item in the combo box and give that to another actionListener which will append a new value to the var from the original actionListener based on which JButton is selected. How can I get the value of var from inside this actionListener and use it in another actionListener that is also in the same constructor? Is that even possible? Is there a better approach?
Your actionPerformed() method will get executed as when its event occurs, but this is not the case with print statement outside the actionPerformed().
So this statement
System.out.println(var); // prints 0 but why not desired value???
gets executed whenever you create an object of your test class (It is preferred to name it Test class according to Java naming conventions) because the print statement is written inside the constructor. In contrast, your print statement inside the actionPerformed method will get executed and print the correct value which you is your "desired value", whenever the event occurs.
Scenario: I have a series of jbuttons (created at runtime) and each of them has a number in his label. Buttons are created with this code:
for (int i = 1; i <= tablesNumber; i++) {
JButton button = new JButton(Integer.toString(i));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Orders().setVisible(true);
}
});
jPanel1.add(button);
}
I need to pass to the class Orders the number of the button which fires the event, e.g. if the user clicks on button number 5 I need to pass the value 5 to Orders.
How can I do this?
Thanks.
From your question:
pass to the class Orders the number of the button which fires the event
You could just capture the loop iteration variable i so it can be used inside your anonymous event handler. For the sake of argument I have assumed you want to pass the number into the constructor, but you can use it however you like:
for (int i = 1; i <= tablesNumber; i++) {
final int t = i; // <-- NEW LINE HERE
JButton button = new JButton(Integer.toString(i));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new Orders(t).setVisible(true); // <-- USE t here however you need to
}
});
jPanel1.add(button);
}
Without final int t = i you may get the compiler error "Cannot refer to a non-final variable i inside an inner class defined in a different method". This is because a capture variable (i.e. a variable from an outer scope used inside an anonymous class' method must be final (or effectively final - this behaviour has changed slightly as of SE 8).
I have a 2D-Array of JButtons
JButton[][] ledBtns = new JButton[8][8];
And in a loop, I do all the init stuff. Now I want to add an EventListener to each JButton, that fires when the Button os clicked. Then I want to change the image on the Button.
for(int i = 0; i < ledBtns.length; i++){
for(int j = 0; j < ledBtns[i].length; j++){
//init stuff
ledBtns[i][j].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
changeImage();
}
});
}
}
Now 'changeImage()' will be called, but I need to know what button called it.
I can't use parameters, if I do it tells me to declare them as 'final'.
Is there any other way than writing 64 methods, that do exactly the same, and adding them manually to each of the JButtons?
The ActionEvent class has a getSource() method used to get the component that generated the event.
The easiest way to do this is to just declare two temporary final ints, and reference those.
for(int i = 0; i < ledBtns.length; i++){
for(int j = 0; j < ledBtns[i].length; j++){
//init stuff
final int finalI = i;
final int finalJ = j;
ledBtns[i][j].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
changeImage(finalI,finalJ);
}
});
}
You can set the JButton object's "name" property and, according to mre's answer, you can call the getSource() method. So you can identity whick button is clicked
Another option is to have your class implement ActionListner (ie, implements ActionListner).
Then when you cycle through your buttons in your loop, you can just say
ledBtns[i][j].addActionListener(this).
Of course, then you have to figure out which object was the source of the event (usually by using if...else blocks). Now that could get unwieldy for 64 objects, but for lesser items, it isn't usually a problem.
Or, you could have the actionPerformed method call change image and pass in the button object, etc to do your work on.
What I've suggested is just another option. I'd do what makes the most sense for your code and is the cleanest and most readable.