EventHandler<T extends Event> in JavaFX a class or interface - java

I have picked a basic example of printing "Hello World" on screen when the mouse is clicked The code goes like this.
package sample;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author gauravp
*/
public class Sample extends Application {
/**
* #param args the command line arguments
*/
Button btn = new Button("ok");
//Label l = new Label("Done");
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("First Stage");
//Created anonymous inner class EventHandler<ActionEvent>
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.print("Hello World !!");
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
In documentation it is mentioned that EventHandler is an interface , but how come the interface be instantiated...
"new EventHandler<ActionEvent>()"
In a lot of confusion....please reply if you have any idea.. Here is the link
for the EventHandler interface :
http://docs.oracle.com/javafx/2.0/api/javafx/event/EventHandler.html

The syntax
new EventHandler<ActionEvent>() {
#Override // <- notice the annotation, it overrides from the interface.
public void handle(ActionEvent event) {
System.out.print("Hello World !!");
}
}
creates an "anonymous inner class" that implements EventHandler, and defines the handle method. If you inspect the classes generated when you compile your project, you will probably find a class file named Sample$1 (or similar) which is the class generated for this code.
You can read up on inner (anonymous) classes here: http://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html
To answer your question: EventHandler is an interface, and this code doesn't actually create an instance of it, but an instance of the newly declared anonymous class.

What you're seeing there is an anonymous inner class.
It's an implementation of the interface "on the spot", without creating a separate class with a name that implements the interface.
Anonymous inner classes are often used for event handlers of GUI components, as your example code shows.

Related

Is it possible to define a scene in a separate class?

This may have been asked before but i was not able to find an answer. Im working on a JavaFX app that contains a lot of scenes and a lot of animation. Currently I'm having different Animationtimers and different Scenes all defined inside the start() function, inside the main class that extends Application. However the code gets very messy and long.
Is there a way in which you can define all of these things in a separate Java class, and then simply do something like primaryStage.setScene(MyScene.getScene) - MyScene being the java class that has all your scene code.
Something like this:
public class TestScene {
private Group root = new Group();
Scene test = new Scene(root);
Button button = new Button("test");
root.getChildren.add(button);
}
And actually having that code be a scene that you can just import and set on primaryStage.
Edit: I have no idea why this was so difficult for my mind, as Bertijn said I obviously just need to use a constructer. For whatever reason I forgot that, and so I obviously couldent perform a root.getChildren.add(button), outside a function of some sort.
If anybody else struggles with this here is the super simple solution:
Class containing our scene:
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.paint.Color;
public class OurScene {
public Scene getScene() {
Group root = new Group();
Scene scene = new Scene(root, Color.GREEN);
Button button = new Button("Hello world!");
root.getChildren().add(button);
return scene;
}
}
And then to add it to primaryStage:
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
OurScene ourScene = new OurScene();
primaryStage.setScene(ourScene.getScene());
primaryStage.show();
}
}
Try making a class called Scenes. In the constructor, created all your scenes, you can give them an id if you want. In your main class, just create an instance of this class Scenes scenes = new Scenes();. The scenes get created. Then you can access them by creating a getScene(String id) method.
Hope I understand your question correctly, and if this doesn't answer it, feel free to get back to me!

Can I use multiple classes to control one FXML file?

I made an application in Scene Builder on one FXML. I am making a server with JavaFX so I can learn JavaFX and get more familiar with Java's networking libraries.
I have a server terminal Tab and additional tabs within a TabPane. I wanted to make classes that extend upon the main controller class to handle components in each tab.
While trying to implement this I found that the FXMLLoader won't be able to read things if the #FXML annotated variables are static. And the #FXML annotated event listener method won't be read if that is static either.
And if I try any kind of workaround I get nullpointerexceptions when trying to change text in the TextArea. I really don't want to have to use multiple FXML files but it's seeming like I'll have to because if I can't make these static then it just won't work.
Within the Server Terminal Tab there is a TextArea, a TextField, and a Button.
Here's my working code:
package me.Cronin.Keith.JavaServer;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
public class JavaServer extends Application {
#FXML
public Button btnSendCommand;
#FXML
public TextField consoleInputField;
#FXML
public TextArea serverTerminal;
public static FXMLLoader fxmlLoader = new FXMLLoader(JavaServer.class.getResource("JavaServer.fxml"));
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage stage) throws IOException
{
Parent p = fxmlLoader.load();
Scene scene = new Scene(p);
stage.setTitle("Java Server v1.0");
stage.setScene(scene);
stage.show();
}
#FXML
public void clickSendCommand(MouseEvent event)
{
serverTerminal.setText("I got clicked..");
}
}
Here's the other class that I don't know what to do with yet:
package me.Cronin.Keith.JavaServer.Terminal;
import me.Cronin.Keith.JavaServer.JavaServer;
public class Terminal extends JavaServer {
public static void logTerminal(String msg)
{
}
}
Is there anything I can do to change this to support what I want to do?
I want to be able to control the variables (JavaFX Components from FXML) in JavaServer.class with my other classes that extend upon it.
I have seen this question here:
Multiple controller for one FXML file
But it doesn't answer my question.
It's seeming like I'd have to put everything in the main controller class or have multiple Fxml files.
I was able to make this work by replacing my Terminal class with this:
Terminal.java
package me.Cronin.Keith.JavaServer.Terminal;
import me.Cronin.Keith.JavaServer.JavaServer;
public class Terminal extends JavaServer {
public static void logTerminal(String msg)
{
JavaServer mainController = fxmlLoader.getController();
mainController.serverTerminal.setText(msg + "\n");
}
}
So the answer is YES you can.
In JavaServer.java I just called Terminal.class statically and then used the static method logTerminal() within it which worked. I extended JavaServer.java in Terminal.java so I could statically call the controller's FXMLLoader.

Dynamically adding checkboxes in JavaFX

I'm trying to create a game prediction system in Java with GUI based on JavaFX using scene builder. It contains a HashMap containing a game object in which there is an ArrayList containing the participating athletes. Both of which will be decided by the user at runtime. Only a certain type of athletes will be eligible for participating in a certain type for a game, for example, swimmers will be able to participate only in swimming games. I can get the eligible athletes at by matching their types with game object and athlete object, but how do I create the checkboxes(for the eligible athletes at runtime?
You can use following approach to add or remove checkboxes at runtime
package com.grsdev.stackoverflow.question170919.pack02;
import javafx.application.*;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* #author gaurav salvi
*
*/
public class JavaFxCheckBoxDemo extends Application{
private static VBox root;
private static CheckBox box=new CheckBox("Apple");
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
root=new VBox();
Button button=new Button(" toggle ");
button.setOnAction(JavaFxCheckBoxDemo::buttonClicked);
root.getChildren().add(button);
root.getChildren().add(box);
Scene value=new Scene(root,200,200);
stage.setScene(value);
stage.show();
}
private static void buttonClicked(ActionEvent event){
if(root.getChildren().contains(box)){
root.getChildren().remove(box);
}else{
root.getChildren().add(box);
}
}
}
I think, dynamically creating objects in Scene Builder and linking them in the controller on basis of their ID would very difficult if not impossible. One possible workaround for the given problem would be adding several static objects and set their visibility to hidden. As and how athletes were created and getting added to the ArrayList in the Game object I changed the visibility for the given checkbox.

button.onActionProperty().addListener is not working in javafx

I am new in Java and I am trying Java events but I am absolutely lost. I know events from C# where is no problem with it and they works perfectly, but Java is different universe . I tried to find something on internet but I can't figured it out long time so I am here.
I have one object and I need trigger some action. When this action is triggered I need to call not only one event handler, but more of them from different objects.
For example I just use Button class.
There are two ways how to do that:
One way is to use button.setOnAction method. But this is not working because when I call this method second time (from another object) I just replace one event handler by another. You can see what I mean in code in method initEventsUselessWay().
Second way is to use button.onActionProperty().addListener. But this is not working at all. You can see in method initEventsNeededWay().
So, why button.onActionProperty().addListeneris not working?
And is there any way how to do this in Javafx?
Finally I will not use Button class, but something like MyClass and I need to implement this here. But if this is not working on Button class it will not work on MyClas neither.
Thank you very much for advice.
package sample;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class JavaEventsTest1589 extends Application {
private Button btnDemo1;
private Button btnDemo2;
#Override
public void start(Stage primaryStage) {
// panel
Pane rootPane = new Pane();
// scene
Scene scene = new Scene(rootPane, 300, 250);
primaryStage.setTitle("events demo");
primaryStage.setScene(scene);
// button 1
btnDemo1 = new Button();
rootPane.getChildren().add(btnDemo1);
btnDemo1.setText("Execute Demo 1");
btnDemo1.setLayoutX(50);
btnDemo1.setLayoutY(10);
// button 2
btnDemo2 = new Button();
rootPane.getChildren().add(btnDemo2);
btnDemo2.setText("Execute Demo 2");
btnDemo2.setLayoutX(50);
btnDemo2.setLayoutY(50);
initEventsUselessWay();
initEventsNeededWay();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
private void initEventsUselessWay() {
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
}
});
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
runDemoSecondaryReaction();
}
});
}
private void initEventsNeededWay() {
btnDemo2.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
#Override
public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observableValue, EventHandler<ActionEvent> actionEventEventHandler, EventHandler<ActionEvent> actionEventEventHandler2) {
runDemoThisINeed_No1();
}
});
btnDemo2.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
#Override
public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observableValue, EventHandler<ActionEvent> actionEventEventHandler, EventHandler<ActionEvent> actionEventEventHandler2) {
runDemoThisINeed_No2();
}
});
}
private void runDemoPrimaryReaction() {
System.out.println("useless way - primary reaction");
}
private void runDemoSecondaryReaction() {
System.out.println("useless way - secondary reaction");
}
private void runDemoThisINeed_No1() {
System.out.println("not working way - No1");
}
private void runDemoThisINeed_No2() {
System.out.println("not working way - No2");
}
}
Use addEventHandler:
btnDemo1.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
}
});
btnDemo1.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
runDemoSecondaryReaction();
}
});
I recommend using Java 8, in which case you can write
btnDemo1.addEventHandler(ActionEvent.ACTION, event -> runDemoPrimaryReaction());
btnDemo1.addEventHandler(ActionEvent.ACTION, event -> runDemoSecondaryReaction());
The setOnAction(...) method is a "convenience" method. The way it works is that the Button maintains an ObjectProperty<EventHandler<ActionEvent>>. If you set the value of this property (to an EventHandler<ActionEvent>), that event handler will automatically be added to the event handlers for the button. If you set it a second time, since it's just a property, it will replace the existing event handler. So you can use this for a slightly quicker approach in the case you only have one handler. (It also plays nicely with FXML.)
onActionProperty().addListener(...) is a different thing entirely: it listens for changes in the property itself. So if you register a listener in this way, then call setOnAction(...), the listener you registered with the property will be invoked when you call setOnAction (not when the button is pressed).
Have a look at the tutorial, particularly the first section "Processing events" and the second "Working with convenience methods". The second section makes it clear when setOnAction is actually doing.
You need to think of an 'action' as a property of the Button rather than an event.
A Button can only have one action at a time, hence you are setting it to one value and then changing it to another which means only the code in the second handler will execute.
The action property is implemented using one of the JavaFX property classes which provides built in property change notification. When you call button.onActionProperty().addListener(... you are adding a listener that will be invoked when the action is changed.
Try calling the addListener(... code before calling setOnAction(... and it should be clear what is happening.
If you want to think of this in terms of C# then
button.setOnAction(.. is like a property e.g. button.Action = ...
button.onActionProperty().addListener(... is like an event e.g. button.ActionChanged += ...
If you are new to JavaFX and need some help with their particular implementation of properties and events I can suggest the following resources:
Creating JavaFX Properties
Creating read-only properties in JavaFX
JavaFX: Handling events
JavaFX: Using properties and binding
Update:
After reading your comments I realise this isn't really JavaFX specific but about events in general. Events are just an implementation of the observer pattern (even in C#).
A basic implementation might look something like this although there is little point in writing this yourself as JavaFX does include a built in way registering listeners for events as demonstrated by James_D.
public interface MyListener {
invoke();
}
class MyButton extends Button {
List<MyListener> listeners = new ArrayList<MyListener>();
public void addListener(MyListener toAdd) {
listeners.add(toAdd);
}
private void invoke() {
for (HelloListener l : listeners)
l.invoke();
}
this.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
this.invoke();
}
});
}
Based on the OP's comment
So I exprect that when I click on button "Execute Demo 1" in console I will see in console two rows: 'useless way - primary reaction useless way - secondary reaction'
you need to call both the methods in the same event handler as following:
btnDemo1.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
runDemoPrimaryReaction();
runDemoSecondaryReaction();
}
});

Can someone convert this Java code in to Clojure

Can someone convert this into Clojure, I don't know to do the line setMainWindow(argument) like things....
import com.vaadin.Application;
class something {
public void init() {
Window main = new Window("The Main Window");
setMainWindow(main);
addComponent(new WindowOpener("Window Opener", main));
}
}
Update:
package app;
import com.vaadin.Application;
import com.vaadin.ui.Button;
import com.vaadin.ui.Window;
/**
* The Application's "main" class
*/
#SuppressWarnings("serial")
public class MyVaadinApplication extends Application{
private Window window;
#Override
public void init(){
window = new Window("My Vaadin Application");
setMainWindow(window);
window.addComponent(new Button("Click Me"));
}
}
There is a "/lib/vaadin.jar" which contains all "com.vaadin.*" things.
I think setMainWindow(window); is from the extended class. I am not going to write that method.
Literal translation:
(defn init []
(let [main (Window. "The Main Window")]
(setMainWindow main)
(addComponent (WindowOpener. "Window Opener" main))))
Though it doesn't make much sense without the context.
See http://dev.vaadin.com/wiki/Articles/ClojureScripting. Also I would suggest http://www.odesk.com.

Categories