im sitting on this for 4 hours now, and once again I end up on Stackoverflow because I just cant solve this (simple) problem.
I want to fire a method when I click a button, Google gives an Example like this:
// Listen for mouse events on the Add button.
addStockButton.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
addStock();
}
});
But this creates a new Instance(?..How can they even create an instance of Clickhandler, since its an Interface) everytime the button is clicked. How can I solve this that all buttons share a Clickhandler and the Handler askes the Button which button he is, so he can fire the method attached to that button.
Any Ideas? If you this is to vage information and you require more code please let me know.
Thanks in advance,
Daniel
Java creates a new instance of an anonymous class that implements ClickHandler. Which it can do because you provide an implementation for the onClick function specified by the interface.
This class is however not created when you click on the button but at the moment you call addClickhandler. If you need the handler for multiple events do something like:
ClickHandler handler = new ClickHandler() {
public void onClick(ClickEvent event) {
addStock();
}
};
addStockButton.addClickHandler(handler);
someOtherButton.addClickHandler(handler);
Within the handler you can identify from where the event is coming using event.getSource().
If you have access to your button variables you could simply check the pointer
if (addStockButton == event.getSource()) ...
Or you can cast the result of getSource to the appropriate type and access the properties/methods of the object.
Eelke has already answered your question. I just add that if you would use GWT's UiBinder feature, you could achieve what you want like this:
#UiField
Button addStockButton;
#UiField
Button removeStockButton;
#UiHandler({ "addStockButton", "removeStockButton" })
void handleClickEvents(ClickEvent event)
{
if (event.getSource() == addStockButton)
{
addStock();
}
else if (event.getSource() == removeStockButton)
{
removeStock();
}
}
Its an anonymous instance of the interface, this is like declaring a new class that implements that interface.
I would have to ask why you would want to do this, you would need to make the ClickHandler contain a reference to its parent. You would also need to make the buttons identifiable so you can select the right one in the body of the ClickHandler. Is your need to only have a single instance really that bad that you can't have multiple anonymous instances ?
Related
I am in the process of refactoring my application and my teacher recommended that I replace the GUI builder generated code with a more generic one.
Right now every JMenuItem has its own action listener. What I'm trying to achieve is a sort of generic control function for every menu item by using enums in a single action listener. The code below should give you a general idea. clE is the enum key and I believe the enum should implement an interface for reading its label.
I've been doing a bit of research and I'm sure it's something simple, but I can't get fully grasp it yet. Thanks in advance!
public class JECheckBox<E extends ENUM_Label_INTF<?>> extends JCheckBox {
private final E clE;
// +++++++ CONSTRUCTOR +++++++++
public JECheckBox(final E clE) {
super( ((GetLabelINTF) clE).GetLabel() );
this.clE = clE;
}
public E GetKey() {
return clE;
}
}
I believe the enum should implement an interface for reading its label.
If you want to read the text of the check box, then you create a generic listener by doing something like:
Action action = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
JCheckBox checkbox = (JCheckBox)e.getSource();
System.out.println( checkbox.getText() );
}
};
Now you can add the Action to each check box.
Note an Action is a more versatile ActionListener. Read the section from the Swing tutorial on How to Use Actions for more information and examples.
Not suew what you mean by generic enums. Try giving every menu item (or any component) it's own name using component.setName(SomeEnum.soneValue.toString()). Then get the name in the action listener and do a switch(SomeEnum.valueOf(name).
I feel that I'm missing something when it comes to statically typed languages. When I pretty much only used perl way back, there were many ways I could tell an object which function to call.
Now that I'm in Java, I fail to see how I can do something similar in an easy fasion
I have a generic Button class. This is subclassed by all of the actual buttons that will be used: Each with a different method to call when clicked.
Is there really no way of passing a reference to a method to call when clicked, so that I can use one class for all of the buttons?
At present, I create buttons like this:
// Specifically using the subclass that sets "firemode" to "close"
FiremodeClose fc = new FiremodeClose(Settings.ui_panel_start, Settings.ui_panel_row_firemode, game);
painter.addSelectionButton(fc);
clickTracker.addSelectionButton(fc);
This ofcourse couses a myriad of subclasses, each one differing only in placement, label/graphics, and method call. It makes more sense to do something similar to this:
// Generic button, the method that sets "firemode" is somehow passed as arguement to the contsructor.
Button fc = new Button(&referenceToFunctionToCallWhenClicked, otherArguementsEtc);
painter.addSelectionButton(fc);
clickTracker.addSelectionButton(fc);
Like I said, I feel I must be missing something, because it makes sense that there should be a way of achieving this, thus letting me getting away with just one Button class without any subclasses.
If that's what interfaces are for, then I must've been using them for something else than their intended purpose. I'd love to see an answer involving some code examples for this.
Have your Buttons implement the observer pattern, just like Swing does. Then you can even just use Swing's ActionListener interface, or even Runnable is not a bad choice, or e.g. roll your own:
// Your interface.
public interface MyButtonListener {
public void buttonClicked ();
}
// Somewhere else:
Button fc = ...;
fc.addButtonListener(new MyButtonListener () {
#Override public void buttonClicked () {
// do stuff here
}
});
// And in your Button have it simply iterate through all of its registered
// MyButtonListeners and call their buttonClicked() methods.
There are myriads of other ways to implement this. For example, you could even do something like:
public interface ThingThatCaresAboutButtons {
public void buttonClicked (Button button);
}
Then have your higher level UI logic be something like:
public class MyUI implements ThingThatCaresAboutButtons {
#Override public void buttonClicked (Button button) {
if (button == theOneButton) {
// do whatever
} else if (button == theOtherButton) {
// do whatever
}
}
}
And when creating buttons:
theOneButton = new Button(theUI, ...);
theOtherButton = new Button(theUI, ...);
Or have them maintain a list instead of a single object passed in the constructor. Or whatever.
Endless ways to skin this cat but hopefully you get some inspiration here. Check out how Swing works.
You could for instance use Runnable:
class MyButton {
private final Runnable action;
public MyButton(Runnable action) {
this.action = action;
}
...
}
And then call action.run() when the button is clicked.
Then when creating a button, you can pass a reference to a method, as long as it has the void return type, and takes no arguments.
Button fc = new Button(EnclosingClass::methodToCall, otherArguementsEtc);
Other interfaces can be used for different method signatures.
In Java 8 you can use both method references and lambdas:
class Button {
Button(Runnable function) {
}
}
Button b1 = new Button(() -> System.out.println("works!"));
Button b2 = new Button(System::gc);
You can do similar thing in Java <8, but it's more verbose with anonymous classes:
Button b3 = new Button(new Runnable() {
#Override
public void run() {
System.out.println("works!");
}
});
I'm making a simple calculator, so far I did a text field where I can type numbers and it listens if key was typed from keyboard.
private void resultKeyTyped(java.awt.event.KeyEvent evt) { }
What I want is to click on let's say '1' with mouse and send a key event to this method, so it would be like I clicked it on keyboard. Tried doing keypress with robot but it says 'void type is no good here' or something like that. I wanted to just run that resultKeyTyped method from withing mouse click listener, like this:
private void jButton1MouseClicked(java.awt.event.MouseEvent evt)
{
resultKeyTyped(KeyEvent.VK_1);
}
To call the resultKeyTyped, you have to pass a KeyEvent. You can just create a KeyEvent using appropriate constructor:
KeyEvent event = new KeyEvent(textField, 0, System.currentTimeMillis(), 0, KeyEvent.VK_1);
resultKeyTypes(event);
Although from your description (eg simple calculator), it sounds like you may wish to choose a different approach:
Add an ActionListener to the JButton
Within the implementation of the ActionListener, change the JTextField text by using the setText method
The best way to do this (assuming that you are clicking on a Button instead of something else) in my opinion would be this:
Button button1 = new Button("1");
button1.addActionListener(new ActionListener() {
int thisKey = KeyEvent.VK_1;
#Override
public void actionPerformed(ActionEvent e) {
resultKeyTyped(thisKey);
}
});
Now, the one thing that you need to change is that resultKeyTyped needs to take an int as a parameter instead of a keyevent. From what I understand, all that you care about is which key was pressed, not how long it was pressed or anything like that. So, wherever you call resultKeyTyped, pass it KeyEvent.getKey()
Hopefully this helped!
P.S. if you really want a keyevent, you can use the keyevent constructor, but since you were using a robot anyways, I am pretty sure that you only care about the key
I would like to know how can I inform a specific class that action has happened? I heard there is something called "callbacks" but I didn't understand how exactly I can use it.
Like the people above commented on you're post, you can do that with listener interfaces or with adapters that implement the required interface.
For example:
You have a JButton (called button) on the JFrame, you can click the button but nothing really happens.
What you will need to do is add the functionality, this can be done by adding a listener to the button, but first u need to create the listener!
The created listener:
public class TestClickedListener extends MouseAdapter {
//The button text will be set to: Clicked!
public void mouseClicked(MouseEvent source) {
JButton buttonSource = (JButton)source.getSource();
buttonSource.setText("Clicked!");
}
}
In the main method of the JFrame u can then add the created MouseListener to the button:
public static void main(String args[]) {
button.addMouseListener(new TestClickedListener());
}
Now try and click the button ;)
I hope this wil help you out buddy, just a simple example to understand it :) !
I'm quite new to interface design and struggling to figure out what the best way to handle events is. In the straight forward case of the handler and the (in this case) buttons causing the event being in the same class, that's fine, I get it. The handler can see the buttons so that it can say:
if (event.getSource() == myButton)
and also, the handler is in the same class so it can add tabs to an object local to that class or similar.
Problem: I don't know how I should be dealing with the case when the handlers and event generators are in different classes.
e.g.
From my main layout class I create and show a custom dialog. That dialog is implemented in its own class. Ideally dialog would use the handler from the main layout class (it implements ClickHandler), which would be fine, but my application has a few different ClickEvents. I distinguish between them as above by checking the source. In this case the buttons are in the dialog class though, so I can't simply say:
if (event.getSource() == myDialogbutton)
as myDialogButton is not in scope.
Any hints for how this should work would be appreciated.
D
Perhaps I can help you with my solution ...
I inherited ClickHandler to an own class which is generic. You can give the ClickHandler any kind of object you want and will be able to access it from the method within.
Example:
import com.google.gwt.event.dom.client.ClickHandler;
public abstract class ClickHandlerData<T> implements ClickHandler {
private T data;
public ClickHandlerData(T data)
{
this.data = data;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
}
Now, in case of a button:
Button btn = new Button("click me");
btn.addClickHandler(new ClickHandlerData<Button>(btn)) {
public void onClick(ClickEvent event) {
Button btn = getData();
...
}
}
I use this class to pass parameters like Integers or something else to the ClickHandler. For instance:
for (int i=0;i<10;i++)
{
Button btn = new Button("click me");
btn.addClickHandler(new ClickHandlerData<Integer>(i)) {
public void onClick(ClickEvent event) {
Window.alert("you klicked button "+getData());
...
}
}
}
I also do the same for AsyncCallbacks, for Commands, for everything else I need to pass data to.
Hope this helped you a bit.
It appears to me that you are trying to use one listener for multiple buttons, unless several of the buttons have the same function they should have different listeners.
In general you should try to have one listener per function, instead of one listener per "event generator".
If you have for example a logout button, it may have a listener from the LoginStatusWidget (displaying who the client is logged in as) and a listener from an object responsable of notefying the server of the logout.
It will serve to seperate the components from each other.
At first i recommend you to try to collect your Buttons and their ClickHandlers in the same class, but if in your case it is not possible, I have a suggestion to you:
When you are creating your Button you can add some information to them:
Button button = new Button("submit");
button.setLayoutData(someObj);
And then after firing event you can get your Button from event in your ClickHandler and find out which button it is :
Button button = (Button) event.getSource();
MetaData someObj = (MetaData) button.getLayoutData();
Try creating a new listener for each anonymous or serial widget e.g. button in a FlexTable. That way their life cycles are connected and they only refer to each other.
Extend the widget
Give it an id and add it to the constructor [make sure the id is one of a kind]
Implement the listener class.
create a new instance of the listener each time you create an item of the same kind.
I'm guessing there are specific objects connected to the widgets. If so keep a HashMap.
May the force be with you
Can't you just do:
final Button source= new Button("My Button");
button.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
doSomething(source);
}
}
Note the button instance has to be marked final.