Java: How to remove anonymous ActionListeners? - java

I am creating a quiz for school. There are several buttons for the questions which, when pressed, display the new question and create 4 different ActionListeners for the buttons of the 4 answers.
Now I need to remove the 4 ActionListeners after one button was pressed.
I am able to remove the ActionListener from the button itself, but I want to remove the other 3 ActionListeners as well.
Every new ActionListener looks like this:
btAnswer1.addActionListener(new java.awt.event.ActionListener()
{
#Override
public void actionPerformed(java.awt.event.ActionEvent evt)
{
lResult.setForeground(Color.red);
lResult.setText("Wrong Answer :(");
// The team is changed.
if (aktTeam == 1)
{
aktTeam = 2;
lAktTeam.setText("Team 2");
}
else
{
aktTeam = 1;
lAktTeam.setText("Team 1");
}
// Here, this ActionListener is removed. But the others should
// be removed too.
btAntwort1.removeActionListener(this);
}
});
I hope somebody can help. :)
Edit: Solved by davidxxx. Thanks!

1) In your example you don't remove the ActionListener from the same btn on the which one you have added the listener:
You add it to btAnswer1:
btAnswer1.addActionListener(new java.awt.event.ActionListener()...
But you remove it from btAntwort1:
btAntwort1.removeActionListener(this);
So, it should not work.
Now I need to remove the 4 ActionListeners after one button was
pressed.
2) If removing all the ActionListeners associated to the Button is valid in our use case, you can do :
for( ActionListener listener : btAntwort1.getActionListeners() ) {
btAntwort1.removeActionListener(listener);
}
Otherwise if you don't want to remove all the ActionListeners associated to the button, you should not inline the anonymous ActionListener instances in order to keep a reference on them when you want to remove them from the button.
For example do that :
ActionListener actionListenerOne = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
...
}
};
ActionListener actionListenerTwo = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
...
}
};
Now you have for example two references on the ActionListener instances you may add to the button.
So you may do :
JButton button = ...;
button.addActionListener(actionListenerOne);
button.addActionListener(actionListenerTwo);
and later :
button.removeActionListener(actionListenerOne);
button.removeActionListener(actionListenerTwo);

Related

Java GUI adding buttons with a for loop

Hi i am making a lotto gui where the user picks 4 numbers from a selection of 28. The way i am currently doing it is as follows
private void no1InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
numberSelectionList.add("1");
}
private void no2InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
chosenNumDisplayLabel.setText(chosenNumDisplayLabel.getText()+" 2");
}
private void no3InputButtonActionPerformed(java.awt.event.ActionEvent evt) {
chosenNumDisplayLabel.setText(chosenNumDisplayLabel.getText()+" 3");
}
etc up through the 28 numbers.
Is there a way to add the actions to each button through a for loop
as this seems more logical?
Also is there a way to add each number picked into an array?
Create a single Action that can be shared by all buttons. The Action will then simply get the text of the button and then do some processing.
Check out setText method with panel and button. This example will show you how to:
create a single ActionListener to be shared by each button
"append" the text to the text field instead of replacing the text
use Key Bindings so the user can also just type the number
On each button you can set an action command:
button.setActionCommand("1");
And you can get the value after that using your ActionEvent:
evt.getActionEvent();
More complete:
ActionListener listener = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
System.out.println(e.getActionCommand()+" clicked");
}
};
int howMuchYouWant = 32;
for(int i = 0; i<howMuchYouWant; i++)
{
JButton button = new JButton(""+(i+1));
button.setActionCommand(""+i);
button.addActionListener(listener);
//add to whatever gui you want here
}

Adding global keybinding for JButtons?

I have:
for (int i = 0; i <= 9; i++) {
JButton c = new JButton();
c.setText(Integer.toString(i));
ActionListener l = new NumericButtonListener(i);
c.addActionListener(l);
buttonGrid.add(c); }
So basically, some code that creates a grid of numbers. How can I map my pane to allow hitting the appropriate number and trigger my NumericButtonListener?
You can use keyBindings and assign one common Action for the specific key.
Make use of button's doClick() function to generate an Action event and listens to it. You will need to invoke this function on the specific button to which mapped key is pressed. For example:
Action generateClick = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
JButton butt = (JButton) e.getSource();
butt.doClick();
}
};
Use keyBinding for each button. See tutorial for KeyBindings
For example add next code in creation:
c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(Integer.toString(i)), "doSomething");
c.getActionMap ().put("doSomething", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(c.getText());
}
});

I cannot seem to .setText more than twice

I am currently making a quiz game. I have managed to set the game up as follows -
The user clicks the start button.
From here this opens a text file and retrieves each question and saves them to a string.
It then adds these strings to an Arraylist.
I then have display the first element of the array to a Label (this is the first question).
From here I have managed to make a method that checks the label text and set the text of 4 buttons to 4 different buttons.
If the user selects the correct answer it adds +1 to a score integer and then moves onto the next question(askQues2();). If the user selects the wrong answer it just moves on to the next question(askQues2();).
Once it starts the next question(askQues2();) it changes all of the values that I have told it to. i.e LabelQuestion and the 4 different answer buttons.
If the user selects the correct answer it adds +1 to a score integer and then moves onto the next question(askQues3();).
THIS IS WHERE THE PROBLEM IS
When I chose an answer during the second question, it does not run the 3rd question method.
CODE
public void askQues1 (){
String askQues1 = questions.get(0);
LabelQuestion.setText(askQues1);
ButAnsA.setText("Gillard");
ButAnsB.setText("Howard");
ButAnsC.setText("Rudd");
ButAnsD.setText("Abbott");
ButAnsA.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
Score += 1;
askQues2();
}
});
ButAnsB.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues2();
}
});
ButAnsC.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues2();
}
});
ButAnsD.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues2();
}
});
}
public void askQues2(){
String askQues2 = questions.get(1);
LabelQuestion.setText(askQues2);
ButAnsA.setText("1999");
ButAnsB.setText("2004");
ButAnsC.setText("2007");
ButAnsD.setText("2010");
ButAnsA.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues3();
}
});
ButAnsA.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues3();
}
});
ButAnsA.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
askQues3();
}
});
ButAnsA.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent a){
Score += 1;
askQues3();
}
});
}
public void askQues3(){
String askQues3 = questions.get(2);
LabelQuestion.setText(askQues3);
ButAnsA.setText("Broncos");
ButAnsB.setText("Knights");
ButAnsC.setText("Storm");
ButAnsD.setText("Dragons");
}
I can tell that it does not load the 3rd method because the question label or answer buttons change.
I have tried multiple options that I have found on the internet. None of them have fixed this problem.
If you require more information. Please let me know. Like I said it is my first time posting a question so I 'm not familiar with standards.
Thanks.
You're adding actionListener to the buttons. I don't think a button can detect more than 2 actions judging by your problem.
Try setting an onClickListener() to the buttons instead.
Code:
ButAnsA.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
askQues3();
}
});
NOTE: There's a difference between adding and setting listeners. By setting a listener every time, you're only replacing the previous one. But by adding a listener you're increasing the number of listeners on the particular widget.
Your askQues2() method is adding action listeners to ButAnsA 4 times, and no new listeners to the other buttons.
You appear to be adding new listeners to the same buttons with every call, which is generally suboptimal. Since you said you are reading the questions and possible answers from a file, you'd be better off including which is the right answer in the file and having a single listener for all buttons.
pseudocode:
doAction(ActionEvent e)
int buttoncode=0
switch (e.getSource())
case ButAnsA:buttoncode=1;
case ButAnsB:buttoncode=2;
case ButAnsC:buttoncode=3;
case ButAnsD:buttoncode=4;
if (questions.get(questnum).rightAnswer == buttoncode)
score++;
questnum++
updateQuestionText()
updateButtonText()

If 2 action listener are registered for same JButton, then prevent execution of listener2 on certain condition

I have a JButton, two action listeners are registered for it. Listener1 will be executed first because it is registered first.
So, what i need is, In a condition matches in the Listener1 then the code of Listener2 should not be executed.
Would you please help me, how to prevent execution of Listener2 if condition matches in Listener1.
JButton jbtn=new JButton();
jbtn.addActionListener(new ActionListener() {
//Listener1
public void actionPerformed(ActionEvent e)
{
if(condition==true){
//do not execute the code of listner2
//stop further executeion of current action
}
}
});
jbtn.addActionListener(new ActionListener() {
//Listener2
public void actionPerformed(ActionEvent e)
{
//some code
}
});
It looks to me as if you may be over-complicating things. Why not simply use one ActionListener or AbstractAction and nest the if block inside:
jbtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(condition) { // no need for the == true part!
myMethod1();
} else { // condition is false
myMethod2();
}
}
});
It's easy. AbstractButton has the method getActionListeners(). So you can remove any listener, added before. Then you can create your listener, which can call the another listener (which was removed from the button).
Something like this:
public class MyActionListener implements ActionListener {
private ActionListener anotherListener;
public MyActionListener(ActionListener another) {
anotherListener = another;
}
public void actionPerformed(ActionEvent ae) {
doSomething();
if (myCondition) {
anotherListener.actionPerformed(ae);
}
}
}
Depending on the exact event you are firing, sometimes you can use consume() / isConsumed(). (e.g. java.awt.event.InputEvent)
Your listeners check for isConsumed() before doing anything, and call consume().
In this way, only one listener will get the event, assuming that they all follow this convention. So if one listener is from an outside or library class this won't help. And the order of which Listener gets the event first may not be under your control.
So #Hovercraft's option may be better. Depends on how decoupled you wish to be.

Multiple buttons and multiple listeners doing various operations Java Swing

How can I have multiple buttons and multiple listeners doing various operations in java swing. Here is an example of what I have, I can redirect to the AddStudent class but the button to redirect to the AddAdult class wont redirect to the AddAdult class.
private class ButtonHandler implements ActionListener {
// handle button event
public void actionPerformed( ActionEvent Student ) {
if ( Student.getSource() == button1 ){
try {
AddStudent newmember = new AddStudent();
newmember.setVisible( true );
} catch ( Exception e1 ) {
e1.printStackTrace();
}
}
}
public void actionPerformed( ActionEvent Adult ) {
if ( Adult.getSource() == button2 ){
try {
AddAdult newmember = new AddAdult();
newmember.setVisible( true );
} catch ( Exception e1 ) {
e1.printStackTrace();
}
}
}
Thanks for any help in advance.
You can attach an ActionListener to each JButton, as explained in the Swing tutorial for buttons
So you will end up with something like
JButton firstButton = ...;
firstButton.addActionListener( myFirstButtonActionListener );
JButton secondButton = ...;
secondButton.addActionListener( mySecondActionListener );
//add them to a UI
contentPane.add( firstButton );
contentPane.add( secondButton );
For more specific questions about your program and your button you will need to provide us with more code then is currently available in your question (in other words, post an SSCCE)
If you want to have multiple handlers, you can define multiple classes each implementing ActionListener interface with appropriate logic implemented and attach it to appropriate buttons.
If you want to use single handler for all buttons, you can use getActionCommand() (more clear than using getSource()) method of ActionEvent to check for the button text and implement your handling logic accordingly using if else.
you have three another ways
1) use Swing Action
myPanel.add(new JButton(new AbstractAction("some narrative") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
//some stuff
}
}));
2) use inner ActionListener
code
myButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
//some stuff
}
});
3) use EventHandler

Categories

Resources