I created 26 JButton in an anonymous actionListener labeled as each letter of the alphabet.
for (int i = 65; i < 91; i++){
final char c = (char)i;
final JButton button = new JButton("" + c);
alphabetPanel.add(button);
button.addActionListener(
new ActionListener () {
public void actionPerformed(ActionEvent e) {
letterGuessed( c );
alphabetPanel.remove(button);
}
});
// set the name of the button
button.setName(c + "");
}
Now I have an anonymous keyListener class, where I would like to disable the button based off of which letter was pressed on the keyboard. So if the user presses A, then the A button is disabled. Is this even possible given my current implementation?
Could you not simply declare an array of 26 JButton objects at class level, so that both listeners can access them? I believe anonymous inner classes can access class variables as well as final variables.
I don't know if you want to disable the button or do you want to remove it? In you code you're calling remove and in your answer you're talking about disabling. You could achieve this by adding a KeyListener to the alphabetPanel. So you could add this just before starting the for-loop:
InputMap iMap = alphabetPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
ActionMap aMap = alphabetPanel.getActionMap();
and instead of your ActionListener added to the JButton call this:
iMap.put(KeyStroke.getKeyStroke(c), "remove"+c);
aMap.put("remove"+c, new AbstractAction(){
public void actionPerformed(ActionEvent e) {
// if you want to remove the button use the following two lines
alphabetPanel.remove(button);
alphabetPanel.revalidate();
// if you just want to disable the button use the following line
button.setEnabled(false);
}
});
You could also iterate through the components, comparing getText() to the key pressed.
As someone else mentioned, anonymous classes can also access members of the outer class as well as local finals
Related
Within two statements that have drastically shortened my code I need to add a statement that adds the text of a JButton to a StringBuilder. The ActionListener statement exists to disable the JButtons when clicked (a nice aesthetic), but I want to include if possible the ability to append the StringBuilder within the ActionListener as well. The following is the two parts of this code.
theModel.randomLetters();
ActionListener disableButton = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
if (!(event.getSource() instanceof JButton)) {
return;
}
theModel.currentWord.append((JButton)event.getSource());
((JButton)event.getSource()).setEnabled(false);
}
};
for (int i = 0; i < 16; i++) {
JButton dice = new JButton(theModel.letters.get(i));
dice.addActionListener(disableButton);
boggleGrid.add(dice);
}
The .addActionListener(disableButton) adds the above ActionListener to each button when it is produced by the for loop. However,
theModel.currentWord.append((JButton)event.getSource());
is what I thought would properly append the StringBuilder "currentWord" with whatever value the clicked button holds (hence "((JButton)event.getSource())"). There are no errors per say but I have written separate lines of code in my main class to test whether there are any changes to the StringBuilder when any buttons are clicked. There isn't.
Where and what do I need to do to properly add the value of the clicked JButton to currentWord?
Using (JButton)event.getSource() will cause the StringBuilder to invoke the objects toString method. This isn't what you want, instead, either use the JButton's text property or the ActionEvent's actionCommand property, for example...
theModel.currentWord.append(((JButton)event.getSource()).getText());
or
theModel.currentWord.append(event.getActionCommand());
instead
Unless you specify the JButton's actionCommand yourself, it will use the buttons text as the actionCommand
I know this sounds very basic, but I never really learned how to do this.
I know about for loops where you can just use for example:
for(int i=0; i<=10; i++)
System.out.println(i);
But that just prints out numbers from 0 to 10 with a gap of 1...which isn't what I'm looking for.
I'm looking for some code where the program starts at a value and adds 1 (or another number) whenever the a button is clicked.
I already have the code for the button and everything, but I have an empty ActionListener as I don't know what to place inside it.
In the ActionListener actionPerformed method write the following code:
public void actionPerformed(ActionEvent event)
{
if(event.getSource() == button_name)
{
count_variable += 1;
}
}
Just add something like this.
int counter = 0;
JButton button = new JButton(" Click me ");
//Add action listener to button
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
counter++;
}
});
This will make counter++ execute whenever the button is pressed. If you want another number, say 10, then just replace counter++ with counter+=10
**disclaimer**
Make sure that counter is accessible inside of ActionPerformed. You can do this by making it a field variable of an encapsulating class, making it a mutable object, and many other ways.
I have a group of loop generated buttons made with this code
this.panelCuerpo.setLayout(new GridLayout(4,5));
for(int i = 1; i<=20; i++){
final JToggleButton b = new JToggleButton(new ImageIcon("/images/available.png"));
panelCuerpo.add(b);
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/available1.png")));
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt){
if(b.isSelected()){
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/busy1.png")));
cantidadBoletas++;
}else{
b.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Images/available1.png")));
cantidadBoletas--;
}
System.out.println(cantidadBoletas);
}
});
}
The problem here is that I can't use setText() to compare later cause there's no property to hide that text. How can I compare it later?
PS. Each button has a consecutive number, it's easy to assign that number. The real problem lies in where to put it.
You could:
Use the Action API, which lets you trigger the selected state of the associated button. This allows you to de-couple the button from the underlying "action" it should take. Take a look at How to Use ActionsHow to Use Actions for more details
Use the actionCommand property of the JButton. This allows you to have some kind of "identifier" associated with the button which is independent of the text
Use an array or List to maintain a reference to the buttons
You can maintain a List<JToggleButton> of JToggleButton and fetch element later by the index. Apart from that instead of adding ActionListener in loop you can implement ActionListener which can be used for all buttons and you just need to write b.addActionListener(this); in loop.
NOTE : better to start from i = 0 instead of 1
I'm trying to make a simple calculator in Java using Swing, and I've created my buttons the following way:
//Our number keypad
public static JPanel numbers(){
//our panel to return
JPanel panel = new JPanel();
//Create and add 3x4 grid layout to panel
GridLayout gl = new GridLayout(3, 4);
panel.setLayout(gl);
//For creating and adding buttons to panel
for(int i = 0; i < 10; i++){
//Create a new button where the name is the value of i
String name = "" + i + "";
JButton button = new JButton(name);
//add action listener
button.addActionListener(handler);
//Add button to panel
panel.add(button);
}
return panel;
}
My question is how do I reference each specific button in my event handler? I can't think of a way to do this without having to manually create each button rather than using a loop.
Thanks.
In your listener, call event.getSource(), and that will return the button which has been pressed. Get the text of the button, and you have its number.
Or create a different instance of your handler for every button, and pass the value of the button (i) to the constructor of the handler. This last solution is cleaner, IMO, because it doesn't depend on the text of the button. If you replaced the text by an image, for example, the first technique wouldn't work anymore.
You can distinguish created buttons by adding the following inside handler:
String buttonText = ((JButton) e.getSource()).getText();
if (<text1>.equals(buttonText)){
//do the stuff
} else if (<text2>.equals(buttonText)){
//do the stuff
} else {
//do the stuff
}
Method #1: go through the child components of the parent JPanel (quite tedious, has to be rebuilt every time you modify the contents of that JPanel). Make sure they're JButtons by using an if . . instanceof clause.
Method #2: as you create them in that loop, add them to a List (or even better, a Map). I prefer a Map personally as it lets me customise the key for that specific JComponent
i.e.
HashMap<String, JComponent> buttonList = new HashMap<String, JComponent>();
for(. .) {
buttonList.put("nameForEachButton", button);
}
I recommend generating the button name based off of the loop counter. Either use your existing name value, or just set it to "button" + i;
Declare your buttons using an array.
JButton[] button = new JButton[9]; //outside the for loop
for (int i = 0; i < 10; i++) {
//put your code
button[i] = new JButton(name);
//your code
}
I have an array I fill with buttons and I want an individual button to change its text when clicked.
for (int i = 0; i<4; i++)
{
button[i] = new JButton ("Add");
button[i].addActionListener(this);
box[i] = new JComboBox();
foodOptions.add(box[i]);
foodOptions.add(button[i]);
}
public void actionPerformed (ActionEvent e)
{
button[this].setText("I've been clicked!");
}
The current doesn't work because of incompatible types, what format is appropriate?
Yes, it makes no sense to pass an object, this, into an array index which expects an int, not your GUI object, so I'm not sure what you were trying to achieve with this.
Just get a reference to the JButton that's been clicked from the ActionEvent's getSource() method:
JButton btn = (JButton)e.getSource();
btn.setText("I've been clicked");
Edit:
Also you should avoid using this as your ActionListener since this means that you're likely having your GUI class implement an ActionListener which is asking the poor class to be too many things, to do too much. You're much better off either using anonymous inner classes or else even better use AbstractActions.