I have the following code:
JButton button = new JButton("Clear");
button.addActionListener(this);
As far as I understand, I create a button on which it is written "Clear". Then I have to associate an action with this button (what will happen if the button is pressed) and it is done by addActionListener. Is it right?
But what I do not understand is where the action is specified. The press of the button should clear text area and, as far as I understand, there should be somewhere a code which clear the text area. But in the given example there is only "this" in the arguments of the addActionListener().
How does the program know that it should clear the text area when the button is pressed?
If it is needed, the full code is given here.
An ActionListener is a callback mechanism. Whenever a control it is added to fires an ActionEvent, the public void actionPerformed(ActionEvent e) method will be invoked.
What I do not understand is where the actionPerformed is called. I see that it is defined within the class but there is no place where this method is called.
This is called by the internal mechanisms of the UI component. Conceptually, you can think of the code looking a bit like this:
public class Button {
private final List<ActionListener> listeners = new ArrayList<ActionListener>();
public void addActionListener(ActionListener l) {
listeners.add(l);
}
public void click() {
ActionEvent event = new ActionEvent(this, 0, "click");
for (ActionListener l : listeners) {
l.actionPerformed(event);
}
}
}
Each JButton, has an EventListenerList. Calling addActionListener(this) adds your ActionListener, a callback function named actionPerformed(), to the list. You can see an outline of the code that calls your method here. The actual fireActionPerformed() method is in AbstractButton. A JButton is a JComponent, which you can see listed among the various classes that use the event listener list mechanism.
You call button.addActionListener( this ), because this implements the interface ActionListener. When the button is clicked, the method actionPerformed(ActionEvent e) (defined by the interface and implemented by your class) is called.
Basically, the mechanism of UI event handling is the JVM queue's events, and each type of event has its subscribers. When an event is fired, like the button is clicked, the JVM will accordingly delegate the processing to the event's subscriber. And this subscriber class has to define the method, or, event handler, to process the event.
In your case, when calling
button.addActionListener(this);
the code actually subscribes this KeyEventDemo instance to the event of type click. Then, when the button is clicked, the KeyEventDemo's method of actionPerformed will be triggered.
Related
I am designing Reversi game in java, and the structure is as follows:
a. A JFrame with 64 buttons in it. The buttons are stored in an array.
b. The JButtons will have black circles or white circles.
So whenever a move is to be made, the program will highlight those boxes where a move can be made, but how can I know which button (I want to know the index of that button) has been clicked when all are highlighted the same way?
From my understanding, you are attempting to detect when a specific JButton is pressed.
The simplest way to do this is by implementing an ActionListener.
public class ExampleClass implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == buttonNameOne)
System.out.println("Button One was pressed");
else if (e.getSource() == buttonNameTwo)
System.out.pringln("Button Two was pressed);
}
}
Detecting an action
The actionPerformed(ActionEvent e) method will activate whenever any button is pressed.
Recording source of action
When it is pressed, it automatically detects the source of this action (the button) and stores it in parameter "e".
Using recorded source of action
By simply doing e.getSource() you are able to get the component which invoked this method and compare it to pre-existing components in your program.
Customized arguments
With each if statement, you are able to customize and personalize the result of the condition (which is if the button being pressed is equal to a specific button). Do this by putting arguments within the body of each conditional statement:
if (e.getSource == sayHiButton)
System.out.println("Hi");
You probably have one ActionListener added to all buttons. Then the ActionEvent getSource passed to performAction has info. That is ugly, like testing the button text.
What is more normal is to use Action (take a look) and setting different actions bearing the 64 states.
public BoardAction extends AbstractAction {
public BoardAction(int x, int y) { ... }
#Override
public void actionPerformed(ActionEvent e) {
...
}
}
JButton button = new JButton(new BoardAction(x, y));
In an Action you can also specify the button caption, and an Action can also be (re)used in a JMenuItem and such.
Because of the extra indirection needed, most examples use an ActionListener,
but swing interna use Action quite often. For instance having an edit menu with cut/copy/pase and a toolbar with cut/copy/paste icons, context menus.
I cant seem to find a way to prevent a SwingWorker from being called twice on a double click.
The issue is that simply setting the JButton to setEnabled(false) doesn't prevent someone from double clicking fast enough to run it more than once.
startButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseReleased(MouseEvent arg0) {
makeItSo();
}
});
private void makeItSo () {
startButton.setEnabled(false);
myWorker myW = new myWorker();
myW.execute(); // Executes allot of work. But errors if this is running more than once.
}
Don't use a MouseListener for buttons, you should be using an ActionListener
See How to Use Buttons, Check Boxes, and Radio Buttons and How to Write an Action Listener for more details
Use ActionListener instead of MouseListener
why you use ActionListener, An ActionListener is used to handle the logical click of a button.
A click happens
- when the mouse is pressed then released on a button,
- when the keyboard shortcut of that button is used,
- when the button has the focus and the space bar is pressed,
- when the button is the default button and Enter is pressed,
- when the button's click() method is called programmatically
A MouseListener only handles low-level mouse events.
When I add a object o1 to a button with addActionListener(), for what actions is the actionPerformed() of o1 called? This is available for JTextField?
actionPerformed is called when user performs any operation on that swing component. ActionListner can be added every Swing component. So yes you can add it on the JTextField. But it gets called only in case if somebody press enter key on JTextField. For other actions you need to add other listners such as DocumentListner.
actionPerformed(ActionEvent e) is a abstract method of ActionListener interface. You should add it following way.
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//............
}
});
Is this available for JtextField?
Yes, this is available for JTextField.
For a JButton the ActionListener is called when the button is clicked.
The ActionListener of a JTextField is fired when Enter is pressed.
This is explained in the documentation.
I have a JscrollPane which holds a JPanel on which I draw. I would like to use the MouseWheelEvent to:
zoom the (with CTRL+Wheel) Panel content
and to scroll the scrollpane (with just the wheel)
Each action by itself works, but I dont't manage to make both work. As soon as I add a MouseWheelListener to the JPanel, the event does not arrive at the JScrollPanels listner.
How can I get the MouseWheelEvent to be forwarded the JScrollPanes MouseWheelListener if it has not been used in the JPanel?
EDIT: Thanks for the hint: Is there also a way to make both listeners listen? Because the scrolling in the scrollpane is actually default implemented. So is there a way to use it without any additional implementation?
Thanks & Regards,
Marc
Make your custom listener dispatch the events (which it doesn't want to handle itself) to the sender's parent, eventually, the scrollPane will pick them up:
final MouseWheelListener wheel = new MouseWheelListener() {
#Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (shouldHandleHere(e)) {
LOG.info("do-my-own-stuff");
} else {
LOG.info("dispatch-to-parent");
e.getComponent().getParent().dispatchEvent(e);
}
}
public boolean shouldHandleHere(MouseWheelEvent e) {
return (e.getModifiersEx() & MouseWheelEvent.CTRL_DOWN_MASK) != 0;
}
};
When you register a listener, you assign a method to execute when a particular behaviour is detected. Suppose I have :
Listener1 executing method1
Listener2 executing method2
If listener1 prevent the listener2 from listening, you just have to call method1 and method2 when listener1 is triggered.
This has been bugging me for a while. If I define setText on a JButton before defining setAction, the text disappears:
JButton test = new JButton();
test.setText("test"); // Before - disappears!
test.setAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// do something
}
});
this.add(test);
If it's after, no problems.
JButton test = new JButton();
test.setAction(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// do something
}
});
test.setText("test"); // After - no problem!
this.add(test);
Furthermore, if I set the text in the JButton constructor, it's fine! Yarghh!
Why does this happen?
As described in the documentation:
Setting the Action results in immediately changing all the properties
described in Swing Components Supporting Action.
Those properties are described here, and include text.
Have a look at
private void setTextFromAction(Action a, boolean propertyChange)
in AbstractButton. You can see it's calling setText() based on the action.
It looks like you can call setHideActionText(true); to sort out your problem.
This is because Action has name for the control as well. Since you are not setting any name in the Action it is getting set to empty string.
1) Listeners put all Events to the EDT,
2) all events are waiting in EDT and output to the screen would be done in one moment
3) you have to split that to the two separate Action inside Listener
setText()
invoke javax.swing.Timer with Action that provide rest of events inside your original ActionListener
If you only want to handle the event, you don't need Action. You can add an ActionListener:
JButton test = new JButton();
test.setText("test");
test.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do something
}
});
this.add(test);
Calling setAction overrides pre-set text.