I have a pane, inside the pane I have a circle and a label. Everytime mouse enter or exit the circle, the label will change to "enter" or "exit". And the label will move accordingly to the mouse position (mouse scenceX and sceneY).
The problem is when I enter the mouse inside the circle, the label will change to "enter" but will immediately change to "exit" then.
I think there is an overlap eventhandler somewhere in my code, but I don't know why. This is my code:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
Pane pane = new Pane();
pane.setStyle("-fx-background-color: grey;");
pane.setPrefSize(300,300);
Circle circle = new Circle();
circle.setFill(Color.TRANSPARENT);
int radius = 50;
circle.setRadius(radius);
circle.setStroke(Color.BLACK);
circle.setStrokeWidth(2);
circle.setLayoutX(100);
circle.setLayoutY(60);
pane.getChildren().add(circle);
Label label = new Label("Mouse point is outside the circle");
pane.getChildren().add(label);
circle.addEventHandler(MouseEvent.MOUSE_EXITED, e -> {
label.setText("Mouse point is outside the circle");
System.out.println("exit");
});
circle.addEventHandler(MouseEvent.MOUSE_ENTERED, e -> {
label.setText("Mouse point is inside the circle");
System.out.println("enter");
});
pane.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {
label.setLayoutX(e.getSceneX());
label.setLayoutY(e.getSceneY());
});
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(pane));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I'm only guessing but I believe the problem is that when the event filter for pane is executed, the result is that the mouse pointer moves from being inside circle to inside label. Then when you move the mouse, it leaves label and enters circle which causes the MOUSE_ENTERED event handler to fire. After that handler fires, the event filter fires which moves the mouse pointer out of circle and into label which causes MOUSE_EXITED event handler to fire. That's why you see enter and exit repeatedly when you move the mouse pointer around inside circle. You don't see enter nor exit at all when you move the mouse pointer around pane when it is outside of circle.
In order to fix it, I removed MOUSE_ENTERED and MOUSE_EXITED and inside the event filter, I check whether the mouse pointer is inside the bounds of circle and set label text accordingly.
Here is the code.
(Note that I replaced addEventFilter with setOnMouseMoved.)
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
Pane pane = new Pane();
pane.setStyle("-fx-background-color: grey;");
pane.setPrefSize(300, 300);
Label label = new Label("Mouse point is outside the circle");
Circle circle = new Circle();
circle.setFill(Color.TRANSPARENT);
int radius = 50;
circle.setRadius(radius);
circle.setStroke(Color.BLACK);
circle.setStrokeWidth(2);
circle.setLayoutX(100);
circle.setLayoutY(60);
Bounds boundingBox = circle.getBoundsInParent();
double maxX = boundingBox.getMaxX();
double minX = boundingBox.getMinX();
double maxY = boundingBox.getMaxY();
double minY = boundingBox.getMinY();
pane.getChildren().add(circle);
pane.getChildren().add(label);
pane.setOnMouseMoved(e -> {
double x = e.getSceneX();
double y = e.getSceneY();
if (minX < x && x < maxX && minY < y && y < maxY) {
label.setText("Mouse point is inside the circle");
}
else {
label.setText("Mouse point is outside the circle");
}
label.setLayoutX(e.getSceneX());
label.setLayoutY(e.getSceneY());
});
primaryStage.setTitle("Hello World");
Scene scene = new Scene(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
As explained in another answer, when the label moves, it moves so that the mouse is now inside the label; this means it is no longer hovering directly over the circle, so an "exited" event is fired on the circle.
The simplest fix is just to make the label ignore the mouse, which can be done using the mouseTransparent property:
Label label = new Label("Mouse point is outside the circle");
label.setMouseTransparent(true);
pane.getChildren().add(label);
Related
I tried drawing a line and changing its end coordinate when dragging.
The problem is, it changes both of the lines' ends, with respect to the middle, supposedly the anchor.
Is there a way to move the anchor to the start of the line?
My code is:
Line path = new Line(30,30, 70 , 75);
path.setStrokeWidth(5);
Circle point = new Circle(3);
point.setCenterX(path.getEndX());
point.setCenterY(path.getEndY());
point.setFill(Paint.valueOf("red"));
point.setOnMouseDragged(e ->{
point.setCenterX(e.getX());
point.setCenterY(e.getY());
path.setEndX(point.getCenterX());
path.setEndY(point.getCenterY());
});
Group shapes = new Group();
shapes.getChildren().addAll(path, point);
BorderPane root = new BorderPane(shapes);
Scene scene = new Scene(root,600,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
the result:
The ideal is that the pivot point will be at the start of the line, and not at the middle.
What you're seeing is not the line growing or shrinking in both directions; instead, what's happening is, as the line changes length, the BorderPane repositions it in order to keep it centered. The same thing is happening with the "rotation". When you move an end in such a way as to change the angle of the line, the bounding box changes in a way that, when the BorderPane repositions the line, causes the other end to move in the opposite direction.
More specifically, the BorderPane is repositioning the Group—effectively the same thing since Group doesn't position its children. One fix for this is to make the Group unmanaged. This will stop the BorderPane from repositioning the Group as its bounds change. Note, however, that this will also stop the Group from contributing to the size and layout calculations of the BorderPane.
Here's an example:
import javafx.application.Application;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class Main extends Application {
private static void installDragHandlers(Circle circle) {
circle.setOnMousePressed(event -> {
Point2D offset = new Point2D(
event.getX() - circle.getCenterX(),
event.getY() - circle.getCenterY()
);
circle.setUserData(offset);
event.consume();
});
circle.setOnMouseDragged(event -> {
Point2D offset = (Point2D) circle.getUserData();
circle.setCenterX(event.getX() - offset.getX());
circle.setCenterY(event.getY() - offset.getY());
event.consume();
});
circle.setOnMouseReleased(event -> {
circle.setUserData(null);
event.consume();
});
}
#Override
public void start(Stage primaryStage) {
Line line = new Line(200, 200, 400, 200);
line.setStrokeWidth(2);
Circle start = new Circle(5, Color.GREEN);
start.centerXProperty().bindBidirectional(line.startXProperty());
start.centerYProperty().bindBidirectional(line.startYProperty());
installDragHandlers(start);
Circle end = new Circle(5, Color.RED);
end.centerXProperty().bindBidirectional(line.endXProperty());
end.centerYProperty().bindBidirectional(line.endYProperty());
installDragHandlers(end);
Group group = new Group(line, start, end);
group.setManaged(false);
primaryStage.setScene(new Scene(new BorderPane(group), 600, 400));
primaryStage.setTitle("SO-55196882");
primaryStage.show();
}
}
The Line is initialized with hard coded start and end points so that it is initially centered in the scene (whose initial dimensions are also hard coded).
Put shapes in group.
public void start(final Stage primaryStage) throws AWTException {
final Line path = new Line(30, 30, 70, 75);
path.setStrokeWidth(5);
final Circle point = new Circle(3);
point.setCenterX(path.getEndX());
point.setCenterY(path.getEndY());
point.setFill(Paint.valueOf("red"));
point.setOnMouseDragged(e -> {
point.setCenterX(e.getX());
point.setCenterY(e.getY());
path.setEndX(point.getCenterX());
path.setEndY(point.getCenterY());
});
final Group root = new Group(path, point);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
I currently have some stack panes on a pane and when dragged with a mouse they move around the pane. I do this by getting the coordinate of the mouse
and the translate x and y of the stack pane when I press the the stack pane. Then when I start to drag the stack pane I set the the translation x and y of the stack pane to the mouse coordinates when I pressed the stack pane + the difference of the new mouse coordinates and the old mouse coordinates.
My problem is after dragging the StackPane the layout x and y stays the same I want to update this as I used this else where.
My event handler when you press the StackPane:
EventHandler<MouseEvent> circleOnMousePressedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
currentStackPane = ((StackPane)(t.getSource()));
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
layoutX = currentStackPane.getLayoutX();
layoutY = currentStackPane.getLayoutY();
}
};
My event handler when i drag the StackPane:
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
currentStackPane.setTranslateX(offsetX);
currentStackPane.setTranslateY(offsetY);
}
};
I tried make a event handler after the drag is finished:
EventHandler<MouseEvent> circleOnMouseReleasedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
currentStackPane.setLayoutX(layoutX + ((StackPane)(t.getSource())).getTranslateX());
currentStackPane.setLayoutY(layoutY + ((StackPane)(t.getSource())).getTranslateY());
currentStackPane.setTranslateX(0);
currentStackPane.setTranslateY(0);
}
};
But this doesn't seem to work. Any help would be appreciated thanks!
EDIT:
I have changed my event handlers. It seems to be updating the layout x and y correctly for the first time I drag the stack pane but when i first drag the stack pane and then release the mouse the stackpane moves to a different position then every time i drag after it messes up completely. Not sure why, any help appreciated!
EDIT2: I realised I set translate x to 0 but didnt set translate y to 0 in the mouse released event. It all works now!
To understand the problem, I would first recommend to have a look at the documentation of layoutX/layoutY properties of a Node.
public final DoubleProperty layoutXProperty
Defines the x coordinate of the translation that is added to this
Node's transform for the purpose of layout. The value should be
computed as the offset required to adjust the position of the node
from its current layoutBounds minX position (which might not be 0) to
the desired location.
For example, if textnode should be positioned at finalX
textnode.setLayoutX(finalX - textnode.getLayoutBounds().getMinX());
Failure to subtract layoutBounds minX may result in misplacement of
the node. The relocate(x, y) method will automatically do the correct
computation and should generally be used over setting layoutX
directly.
The node's final translation will be computed as layoutX + translateX,
where layoutX establishes the node's stable position and translateX
optionally makes dynamic adjustments to that position.
If the node is managed and has a Region as its parent, then the layout
region will set layoutX according to its own layout policy. If the
node is unmanaged or parented by a Group, then the application may set
layoutX directly to position it.
In short,for every node that is rendered in the scene, its position is actually a sum of its layoutX/Y and translateX/Y values in relative to its parent node. The layoutX/Y are initially updated as per its parents layout policy. For that reason, there is no point in updating/relying on layoutX/Y values of node, IF its parent (eg,.StackPane,HBox,VBox,..etc) manages it position.
Pane will not manage/decide its children layout. For that reason the default layoutX/Y values of its children is always 0.
From the above info,if we now look into your code, you are updating the translate values and setting the layout values wrongly. Instead what you have to actually do is:
Take intial values of layoutX/Y.
Update the translateX/Y while dragging.
And on mouse released recompute layoutX/Y values and reset
translateX/Y values.
Below is a quick demo of what I have described.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class PaneLayoutDemo extends Application {
double sceneX, sceneY, layoutX, layoutY;
#Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene sc = new Scene(root, 600, 600);
stage.setScene(sc);
stage.show();
root.getChildren().addAll(getBox("green"), getBox("red"), getBox("yellow"));
}
private StackPane getBox(String color) {
StackPane box = new StackPane();
box.getChildren().add(new Label("Drag me !!"));
box.setStyle("-fx-background-color:" + color + ";-fx-border-width:2px;-fx-border-color:black;");
box.setPrefSize(150, 150);
box.setMaxSize(150, 150);
box.setMinSize(150, 150);
box.setOnMousePressed(e -> {
sceneX = e.getSceneX();
sceneY = e.getSceneY();
layoutX = box.getLayoutX();
layoutY = box.getLayoutY();
System.out.println(color.toUpperCase() + " Box onStart :: layoutX ::" + layoutX + ", layoutY::" + layoutY);
});
box.setOnMouseDragged(e -> {
double offsetX = e.getSceneX() - sceneX;
double offsetY = e.getSceneY() - sceneY;
box.setTranslateX(offsetX);
box.setTranslateY(offsetY);
});
box.setOnMouseReleased(e -> {
// Updating the new layout positions
box.setLayoutX(layoutX + box.getTranslateX());
box.setLayoutY(layoutY + box.getTranslateY());
// Resetting the translate positions
box.setTranslateX(0);
box.setTranslateY(0);
});
return box;
}
public static void main(String[] args) {
Application.launch(args);
}
}
Once you are familiar with the demo, try changing the root from Pane to StackPane and see the behaviour difference.
JavaFx ImageView doesn't trigger Mouse Events such as press or drag if you click or drag on a transparent pixel, is there anyway to work around this and detect mouse events from transparent areas ?
I have this image
that i added into this very simple JavaFX scene
using an ImageView named view and i want to move it with Mouse Drag events
so i wrote this code
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application{
double initMx, initMy,initX, initY;
#Override
public void start(Stage ps) throws Exception {
StackPane pane = new StackPane();
Image im = new Image("0.png");
ImageView view = new ImageView(im);
double fact = im.getWidth() / im.getHeight();
view.setFitHeight(300);
view.setFitWidth(300 * fact);
view.setOnMousePressed(e->{
initX = view.getTranslateX();
initY = view.getTranslateY();
initMx = e.getSceneX();
initMy = e.getSceneY();
});
view.setOnMouseDragged(e->{
double dx = initMx - e.getSceneX();
double dy = initMy - e.getSceneY();
double nx = initX - dx;
double ny = initY - dy;
view.setTranslateX(nx);
view.setTranslateY(ny);
});
pane.getChildren().add(view);
Scene scene = new Scene(pane, 500, 500);
ps.setScene(scene);
ps.show();
}
public static void main(String[] args) {
launch(args);
}
}
this code works fine so far,
but if you press or drag somewhere like under his ears ( or anywhere transparent ) nothing will happen ! how to fix this !
The more natural and easiest solution would have been to just set pick on bounds to true.
view.setPickOnBounds(true);
You can do so by setting this image as a graphic in a Button like so
button.setGraphics(new ImageView(im));
Note: You will need to remove style from the button after adding the ImageView by setting the button background with a transparent background color
Try this, if you didn't yet:
view.setOnMouseDragged(e->{
double dx = initMx - e.getX();
double dy = initMy - e.getY();
I am trying to create a project where the user clicks on the screen and then a rectangle will move to the position where the clicked occurred. My intention was to get the center of the rectangle to move the exact location of the click but my code only moves the rectangle into the general area of where the click occurred. My question is how do I get the center of the rectangle to move the exact location of where a mouse click occurs?
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root,400,400);
Rectangle rec = new Rectangle(50,50,50,50);
rec.setLayoutX(200);
rec.setLayoutY(200);
TranslateTransition transition = new TranslateTransition(Duration.seconds(0.50), rec);
transition.setOnFinished(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
rec.setLayoutX(rec.getTranslateX() + rec.getLayoutX());
rec.setLayoutY(rec.getTranslateY() + rec.getLayoutY());
rec.setTranslateX(0);
rec.setTranslateY(0);
}
});
scene.setOnMousePressed(e->{
transition.setToX(e.getSceneX() - rec.getLayoutX());
transition.setToY(e.getSceneY() - rec.getLayoutY());
transition.playFromStart();
});
root.getChildren().add(rec);
primaryStage.setScene(scene);
primaryStage.show();
}
You ignore the x/y properties of the Rectangle which also shift the position where the Rectangle is drawn. Furthermore for the center to be moved to this position, you need to also subtract half the width/height from the position to move to...
Also I recommend using a Pane instead of BorderPane, is you want to set the layoutX/layoutY properties yourself. Nonetheless in this case it should work too with some small adjustments:
scene.setOnMousePressed(e -> {
transition.setToX(e.getSceneX() - rec.getLayoutX() - rec.getWidth() / 2 - rec.getX());
transition.setToY(e.getSceneY() - rec.getLayoutY() - rec.getHeight() / 2 - rec.getY());
transition.playFromStart();
});
Here a complete sample using a Pane as suggested by fabian.
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Translator extends Application {
private static final double W = 400, H = 400;
private static final double S = 50;
public void start(Stage stage) {
Rectangle rec = new Rectangle(W / 2 - S / 2,H / 2 - S / 2,S,S);
TranslateTransition transition = new TranslateTransition(Duration.millis(500), rec);
transition.setOnFinished(t -> {
rec.setX(rec.getTranslateX() + rec.getX());
rec.setY(rec.getTranslateY() + rec.getY());
rec.setTranslateX(0);
rec.setTranslateY(0);
});
Pane root = new Pane(rec);
Scene scene = new Scene(root,W,H);
root.setOnMousePressed(e -> {
transition.stop();
transition.setToX(e.getX() - S / 2 - rec.getX());
transition.setToY(e.getY() - S / 2 - rec.getY());
transition.playFromStart();
});
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have a Class that extends the CustomMenuItem. This MenuItems are added to a ContextMenu. Now i need to get the X-Coordinates from the right side of the CustomMenuItem.
The Problem is, that I have no idea how I can get the Coordinates.
The CustMenuItem has no function for getting the Coordinates like getX() or getY().
So how can I solve this problem?
This thing I would like to get:
Here we can see a Sample for a Context Menu (red lines). In the Context Menu are a lot of different CustomMenuItems implemented. Now I would like to get the right top corner Coordinate of the CustomMenuItem.
Thank you for your very nice help.
Before dealing with menu items, let's start saying that a ContextMenu is a popup window, so it has Windowproperties. You can ask for (x,y) left, top origin, and for (w,h).
But you have to take into account the effects, since by default it includes a dropshadow. And when it does, there's an extra space added of 24x24 pixels to the right and bottom.
.context-menu {
-fx-effect: dropshadow( gaussian , rgba(0,0,0,0.2) , 12, 0.0 , 0 , 8 );
}
Since this default dropshadow has a radius of 12px, and Y-offset to the bottom of 8px, the right and bottom coordinates of the context menu, including the 24x24 area, are given by:
X=t.getX()+cm.getWidth()-12-24;
Y=t.getY()+cm.getHeight()-(12-8)-24;
where t could be a MouseEvent relative to the scene, and values are hardcoded for simplicity.
Let's see this over an example. Since you don't say how your custom menu items are implemented, I'll just create a simple Menu Item with graphic and text:
private final Label labX = new Label("X: ");
private final Label labY = new Label("Y: ");
#Override
public void start(Stage primaryStage) {
final ContextMenu cm = new ContextMenu();
MenuItem cmItem1 = createMenuItem("mNext", "Next Long Option",t->System.out.println("next"));
MenuItem cmItem2 = createMenuItem("mBack", "Go Back", t->System.out.println("back"));
SeparatorMenuItem sm = new SeparatorMenuItem();
cm.getItems().addAll(cmItem1,cmItem2);
VBox root = new VBox(10,labX,labY);
Scene scene = new Scene(root, 300, 250);
scene.setOnMouseClicked(t->{
if(t.getButton()==MouseButton.SECONDARY || t.isControlDown()){
// t.getX,Y->scene based coordinates
cm.show(scene.getWindow(),t.getX()+scene.getWindow().getX()+scene.getX(),
t.getY()+scene.getWindow().getY()+scene.getY());
labX.setText("Right X: "+(t.getX()+cm.getWidth()-12-24));
labY.setText("Bottom Y: "+(t.getY()+cm.getHeight()-4-24));
}
});
scene.getStylesheets().add(getClass().getResource("root.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setTitle("Scene: "+scene.getWidth()+"x"+scene.getHeight());
}
private MenuItem createMenuItem(String symbol, String text, EventHandler<ActionEvent> t){
MenuItem m=new MenuItem(text);
StackPane g=new StackPane();
g.setPrefSize(24, 24);
g.setId(symbol);
m.setGraphic(g);
m.setOnAction(t);
return m;
}
If you remove the effect:
.context-menu {
-fx-effect: null;
}
then these coordinates are:
X=t.getX()+cm.getWidth();
Y=t.getY()+cm.getHeight();
Now that we have the window, let's go into the items.
MenuItem skin is derived from a (private) ContextMenuContent.MenuItemContainer class, which is a Region where the graphic and text are layed out.
When the context menu is built, all the items are wrapped in a VBox, and all are equally resized, as you can see if you set the border for the item:
.menu-item {
-fx-border-color: black;
-fx-border-width: 1;
}
This is how it looks like:
So the X coordinates of every item on the custom context menu are the same X from their parent (see above, with or without effect), minus 1 pixel of padding (by default).
Note that you could also go via private methods to get dimensions for the items:
ContextMenuContent cmc= (ContextMenuContent)cm.getSkin().getNode();
System.out.println("cmc: "+cmc.getItemsContainer().getBoundsInParent());
Though this is not recommended since private API can change in the future.
EDIT
By request, this is the same code removing lambdas and css.
private final Label labX = new Label("X: ");
private final Label labY = new Label("Y: ");
#Override
public void start(Stage primaryStage) {
final ContextMenu cm = new ContextMenu();
MenuItem cmItem1 = createMenuItem("mNext", "Next Long Option",action);
MenuItem cmItem2 = createMenuItem("mBack", "Go Back", action);
SeparatorMenuItem sm = new SeparatorMenuItem();
cm.getItems().addAll(cmItem1,cmItem2);
VBox root = new VBox(10,labX,labY);
Scene scene = new Scene(root, 300, 250);
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
if(t.getButton()==MouseButton.SECONDARY || t.isControlDown()){
// t.getX,Y->scene based coordinates
cm.show(scene.getWindow(),t.getX()+scene.getWindow().getX()+scene.getX(),
t.getY()+scene.getWindow().getY()+scene.getY());
labX.setText("Right X: "+(t.getX()+cm.getWidth()-12-24));
labY.setText("Bottom Y: "+(t.getY()+cm.getHeight()-4-24));
}
}
});
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.setTitle("Scene: "+scene.getWidth()+"x"+scene.getHeight());
}
private MenuItem createMenuItem(String symbol, String text, EventHandler<ActionEvent> t){
MenuItem m=new MenuItem(text);
StackPane g=new StackPane();
g.setPrefSize(24, 24);
g.setId(symbol);
SVGPath svg = new SVGPath();
svg.setContent("M0,5H2L4,8L8,0H10L5,10H3Z");
m.setGraphic(svg);
m.setOnAction(t);
return m;
}
private final EventHandler<ActionEvent> action = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("action");
}
};