Is it possible to add a ActionEvent Handler to a javaFX Textfield using addEventHandler method? - event-handling

I tried to add action handlers to text field using the addEventHandler() but seem not to be working. Is it even possible o is it a bug? If I try the same with Button control everything is fine.
Here is the sample code:
package com.teste;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class EventHandlerTest extends Application {
#Override
public void start(Stage stage) throws Exception {
// TODO Auto-generated method stub
stage.setTitle("Custom JavaFX Event");
TextField btn = new TextField();
btn.setId("Fire Button");
btn.setText("Fire MyEvent'");
btn.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
if (event.getEventType().equals(ActionEvent.ACTION)) {
System.out.println("ActionEvent 2");
}
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
stage.setScene(new Scene(root, 300, 250));
stage.show();
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
launch(args);
}
}
Documentation says it should be possible, but can't find anything else. Any ideas?

If you use setOnAction rather than addEventHandler, then you will be able to capture the ActionEvent for the TextField.
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent event) {
System.out.println("ActionEvent: " + event);
}
});
I don't know why the addEventHandler code does not capture the event. I also tried addEventFilter as well and that did not work for me either (JavaFX 2.2).
Note that a TextField will generate an ActionEvent when you press the Enter key on the TextField.

In java 8 now is possible
btn.addEventHandler(ActionEvent.ACTION, new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("ActionEvent: " + event);
}
});
//Lambda Notation
btn.addEventHandler(ActionEvent.ACTION, event -> {
System.out.println("ActionEvent: " + event);
});

Related

EventFilter consume() does not prevent SpaceChars in TextField

I have a JavaFX GUI where I wish to intercept the pressing of the SpaceBar and use it to call a method. I wrote an EventFilter that seems to do the trick. It includes the command event.consume() which I believe is supposed to keep the KeyEvent from propagating to the various controls.
My issue is that when I added a TextField, and this field has the focus, the Spacebar presses are not being consumed as I thought they would. The " " are captured by the TextField. I would like to intercept and prevent the " " from being added to the TextField.
What am I leaving out in the code below in order to keep " " from reaching the TextField? The api, if I am reading it correctly, says that filters registered with a parent control can intercept an event before it reaches the children nodes. But even when putting the filter directly on the TextField, I am still having " " chars appear in the TextField.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE)
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
The text field is probably listening for KEY_TYPED events. As is well-documented, getCode() returns KeyCode.UNDEFINED for a KEY_TYPED event. Thus you do not catch this case.
You can check for the character variable as well as the code variable to handle all cases:
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class SpaceIntercept extends Application implements EventHandler <KeyEvent>
{
public static void main(String[] args)
{
Application.launch(args);
}
#Override
public void start(Stage primaryStage)
{
TextField textField = new TextField("asdf");
Group root = new Group();
Scene scene = new Scene(root, 200, 100);
scene.addEventFilter(KeyEvent.ANY, event -> handle(event));
// root.addEventFilter(KeyEvent.ANY, event -> handle(event));
// textField.addEventFilter(KeyEvent.ANY, event -> handle(event));
root.getChildren().add(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void handle(KeyEvent event)
{
if (event.getCode() == KeyCode.SPACE || " ".equals(event.getCharacter()))
{
if (event.getEventType() == KeyEvent.KEY_PRESSED)
{
System.out.println("Code that responds to SpaceBar");
}
event.consume();
}
}
}
A simple solution i can think,which although doesn't blocks the space from being added to the TextField,but it replaces it after it has been added almost instantly is adding a changeListener to the TextProperty of the TextField:
textField.textProperty().addListener((observable,oldValue,newValue)->{
textField.setText(textField.getText().replace(" ", ""));
});
This may also be helpfull http://fxexperience.com/2012/02/restricting-input-on-a-textfield/

How to fire event when scrolling up,javafx

I am developing chat application on java and i want to use function used by facebook to retrieve chat history when user scroll up. I tried "on Scroll" action which fire event whenever scroll reach top or down of scroll bar. Now i want to Fire action event only when scroll bar reach top like in facbook chat box.
Assuming that you have a ScrollPane, you can observe vvalueProperty of it:
scrollPane.vvalueProperty().addListener(
(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
if(newValue.doubleValue() == 0){
System.out.println( "AT TOP" );
// load more items
}
});
and you may also scroll to bottom with
scrollPane.setVvalue( scrollPane.getVmax() );
initially.
Here is the example of what you want. I hope this will help you.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class ScrollUtil extends Application
{
private boolean scrollToBottom = false;
private boolean scrollToTop = false;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(final Stage stage) throws Exception
{
final VBox root = new VBox();
final ScrollPane scrollPane = new ScrollPane();
final VBox vBox = new VBox();
vBox.setAlignment(Pos.BOTTOM_CENTER);
scrollPane.setContent(vBox);
scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
Button button = new Button("add");
Button button3 = new Button("scroll up");
button3.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
scrollToTop = true;
scrollPane.setVvalue(scrollPane.getVmin());
System.out.println("vmin= "+scrollPane.getVmin() + "; vmax = " + scrollPane.getVmax() + "; vvalue" + scrollPane.getVvalue());
}
});
button.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
vBox.getChildren().add(new Label("hallo"));
scrollToBottom = true;
//System.out.println(scrollPane.getVmin() + "; max = " + scrollPane.getVmax() + "; " + scrollPane.getVvalue());
}
});
scrollPane.setVvalue(scrollPane.getVmax());
scrollPane.vvalueProperty().addListener(new ChangeListener<Number>()
{
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue)
{
if(scrollToBottom)
{
scrollPane.setVvalue(scrollPane.getVmax());
scrollToBottom = false;
}
if(newValue.doubleValue() ==0)
{
vBox.getChildren().add(new Label("hallo"));
System.out.println("min value ="+scrollPane.getVmin());
//scrollPane.setVvalue(scrollPane.getVmin());
scrollToTop = true;
System.out.println("now get the chat history");
}
}
});
Button button2 = new Button("scroll");
button2.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent actionEvent)
{
scrollPane.setVvalue(Double.MAX_VALUE);
}
});
root.getChildren().addAll(scrollPane, button, button2, button3);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}

Drag and Drop vbox element with show snapshot in javafx

I want drag an element in vbox as a parent and show node moving during drag and drop of element, how can do this with The slightest change.
Just register mouse listeners with the elements of the VBox. You want to call startFullDrag() on the node on a dragDetected event, and rotate the child nodes of the VBox on a dragReleased event. You can use the dragEntered and dragExited events if you want to give visual hints to the user about the drag.
See the API docs for more.
Simple example (code is way cleaner in JavaFX 8, btw):
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseDragEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
final VBox root = new VBox(5);
final ScrollPane scroller = new ScrollPane();
scroller.setContent(root);
final Scene scene = new Scene(scroller,400,200);
for (int i=1; i<=20; i++) {
final Label label = new Label("Item "+i);
addWithDragging(root, label);
}
// in case user drops node in blank space in root:
root.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
rotateNodes(root, indexOfDraggingNode, root.getChildren().size()-1);
}
});
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
private void addWithDragging(final VBox root, final Label label) {
label.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
label.startFullDrag();
}
});
// next two handlers just an idea how to show the drop target visually:
label.setOnMouseDragEntered(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("-fx-background-color: #ffffa0;");
}
});
label.setOnMouseDragExited(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("");
}
});
label.setOnMouseDragReleased(new EventHandler<MouseDragEvent>() {
#Override
public void handle(MouseDragEvent event) {
label.setStyle("");
int indexOfDraggingNode = root.getChildren().indexOf(event.getGestureSource());
int indexOfDropTarget = root.getChildren().indexOf(label);
rotateNodes(root, indexOfDraggingNode, indexOfDropTarget);
event.consume();
}
});
root.getChildren().add(label);
}
private void rotateNodes(final VBox root, final int indexOfDraggingNode,
final int indexOfDropTarget) {
if (indexOfDraggingNode >= 0 && indexOfDropTarget >= 0) {
final Node node = root.getChildren().remove(indexOfDraggingNode);
root.getChildren().add(indexOfDropTarget, node);
}
}
public static void main(String[] args) {
launch(args);
}
}
This is an addendum to #James_D's excellent answer
This shows how to add an image preview to the draggable node as #James_D suggests in his comment:
private void addPreview(final VBox root, final Label label) {
ImageView imageView = new ImageView(label.snapshot(null, null));
imageView.setManaged(false);
imageView.setMouseTransparent(true);
root.getChildren().add(imageView);
root.setUserData(imageView);
root.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
imageView.relocate(event.getX(), event.getY());
}
});
}
private void removePreview(final VBox root) {
root.setOnMouseDragged(null);
root.getChildren().remove(root.getUserData());
root.setUserData(null);
}
Call addPreview() in label.setOnDragDetected(). Call removePreview() in label.setOnMouseDragReleased() and root.setOnMouseDragReleased().
There is a much better solution that is far cleaner now.
// Root is the node you want to drag, not the scene root.
root.setOnDragDetected(mouseEvent -> {
final ImageView preview = new ImageView(root.snapshot(null, null));
final Dragboard db = root.startDragAndDrop(TransferMode.ANY);
db.setContent( // Set your content to something here.
);
db.setDragView(preview.getImage());
mouseEvent.consume();
});

How to register ClickHandler to a vector grahpic in gwt-graphics and get-plattform

I’m trying to use gwt-graphics in a gwt-plattform project.
When I try to register a ClickHandler of a circle I got an exception:
I can add a ClickHandler to the circle in the view, but how can a add in the presenter?
view:
import org.vaadin.gwtgraphics.client.DrawingArea;
import org.vaadin.gwtgraphics.client.shape.Circle;
import com.gwtplatform.mvp.client.ViewImpl;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.inject.Inject;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PushButton;
public class MainPageView extends ViewImpl implements MainPagePresenter.MyView {
private static String html = "<h1>Web Application Starter Project</h1>\n"
+ "<table align=\"center\">\n"
+ " <tr>\n"
+ " <td colspan=\"2\" style=\"font-weight:bold;\">Please enter your name:</td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td id=\"nameFieldContainer\"></td>\n"
+ " <td id=\"sendButtonContainer\"></td>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td colspan=\"2\" style=\"color:red;\" id=\"errorLabelContainer\"></td>\n"
+ " </tr>\n" + "</table>\n";
private final HTMLPanel panel = new HTMLPanel(html);
private final Label errorLabel;
private final TextBox nameField;
private final Button sendButton;
private AbsolutePanel absolutePanel = new AbsolutePanel();
Image image_1;
Image image;
DrawingArea d;
Circle circle;
#Inject
public MainPageView() {
sendButton = new Button("Send");
nameField = new TextBox();
nameField.setText("GWT User");
errorLabel = new Label();
// We can add style names to widgets
sendButton.addStyleName("sendButton");
// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
panel.add(nameField, "nameFieldContainer");
panel.add(sendButton, "sendButtonContainer");
d = new DrawingArea(500, 500);
panel.add(absolutePanel);
absolutePanel.setHeight("500px");
// circle.addClickHandler(new ClickHandler() {
//
// #Override
// public void onClick(ClickEvent event) {
// Window.alert("image2");
//
// }
// });
image = new Image("ball1.png");
absolutePanel.add(image, 59, 10);
image.setSize("100px", "100px");
image_1 = new Image("Hexagon.svg");
absolutePanel.add(image_1, 115, 10);
image_1.setSize("100px", "100px");
absolutePanel.add(d, 100, 100);
//
Circle circle = new Circle(100, 100, 150);
circle.setStrokeColor("red");
d.add(circle);
panel.add(errorLabel, "errorLabelContainer");
}
#Override
public Widget asWidget() {
return panel;
}
#Override
public HasValue<String> getNameValue() {
return nameField;
}
#Override
public HasClickHandlers getSendClickHandlers() {
return sendButton;
}
#Override
public void resetAndFocus() {
// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();
}
#Override
public void setError(String errorText) {
errorLabel.setText(errorText);
}
// #Override
// public HasClickHandlers getImage1() {
// return image;
// }
//
// #Override
// public HasClickHandlers getImage2() {
// return image_1;
//
// }
#Override
public HasClickHandlers getCircle() {
return circle;
}
}
Presenter:
package mybla.client.core;
import org.vaadin.gwtgraphics.client.shape.Circle;
import com.gwtplatform.mvp.client.Presenter;
import com.gwtplatform.mvp.client.View;
import com.gwtplatform.mvp.client.annotations.ProxyStandard;
import com.gwtplatform.mvp.client.annotations.NameToken;
import mybla.client.place.NameTokens;
import com.gwtplatform.mvp.client.proxy.ProxyPlace;
import com.google.inject.Inject;
import com.google.gwt.event.shared.EventBus;
import com.gwtplatform.mvp.client.proxy.RevealRootContentEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HasValue;
import com.gwtplatform.mvp.client.proxy.PlaceManager;
import com.gwtplatform.mvp.client.proxy.PlaceRequest;
import mybla.shared.FieldVerifier;
public class MainPagePresenter extends
Presenter<MainPagePresenter.MyView, MainPagePresenter.MyProxy> {
public interface MyView extends View {
HasValue<String> getNameValue();
HasClickHandlers getSendClickHandlers();
void resetAndFocus();
void setError(String errorText);
HasClickHandlers getCircle();
// HasClickHandlers getImage2();
//
// HasClickHandlers getImage1();
}
#ProxyStandard
#NameToken(NameTokens.main)
public interface MyProxy extends ProxyPlace<MainPagePresenter> {
}
private final PlaceManager placeManager;
#Inject
public MainPagePresenter(final EventBus eventBus, final MyView view,
final MyProxy proxy, final PlaceManager placeManager) {
super(eventBus, view, proxy);
this.placeManager = placeManager;
}
#Override
protected void revealInParent() {
RevealRootContentEvent.fire(this, this);
}
#Override
protected void onBind() {
super.onBind();
registerHandler(getView().getSendClickHandlers().addClickHandler(
new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
sendNameToServer();
}
}));
// registerHandler(getView().getImage1().addClickHandler(new ClickHandler() {
//
// #Override
// public void onClick(ClickEvent event) {
// Window.alert("image1");
//
// }
// }));
registerHandler(getView().getCircle().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Window.alert("image2");
}
}));
}
#Override
protected void onReset() {
super.onReset();
getView().resetAndFocus();
}
/**
* Send the name from the nameField to the server and wait for a response.
*/
private void sendNameToServer() {
// First, we validate the input.
getView().setError("");
String textToServer = getView().getNameValue().getValue();
if (!FieldVerifier.isValidName(textToServer)) {
getView().setError("Please enter at least four characters");
return;
}
// Then, we transmit it to the ResponsePresenter, which will do the server call
placeManager.revealPlace(new PlaceRequest(NameTokens.response).with(
ResponsePresenter.textToServerParam, textToServer));
}
}
In your presenter:
getView().getCircle().addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event)
{
Window.alert("image2");
}
});
This will use the getter method set in the presenter.view, to access the circle in the View itself.
Looks like the circle you instantiate in your View's constructor is a local variable, not the class-scope variable your getCircle() method returns. Additionally, the commented out code for adding the onclick handler is before the code that instantiates the local variable.
You have:
...
// circle.addClickHandler(new ClickHandler() {
//
// #Override
// public void onClick(ClickEvent event) {
// Window.alert("image2");
// }
// });
...
Circle circle = new Circle(100, 100, 150);
circle.setStrokeColor("red");
d.add(circle);
Change it to:
...
circle = new Circle(100, 100, 150); // This now references the class-scope variable, rather than creating a new local variable.
circle.setStrokeColor("red");
d.add(circle);
circle.addClickHandler(new ClickHandler() { // This will no longer throw a null-pointer exception.
#Override
public void onClick(ClickEvent event) {
Window.alert("image2");
}
});

How do I close a JDialog window using a JButton?

I've tried a bunch of different ways to close the window, but since you can't send additional parameters to to Action Listener method I can't dispose the frame due to a pointer exception for the frame.
This is my current code.
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class errorRequiredFieldMissing extends JDialog{
JLabel error;
JButton exit;
public static JFrame frame;
public errorRequiredFieldMissing() {
super(frame, "Error", true);
setLayout(new FlowLayout());
error = new JLabel ("Required field or fields missing, please fill in all fields to continue.");
add(error);
exit = new JButton ("OK");
add(exit);
System.out.println("chk1");
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("chk2");
frame.dispose();
}
});
}
public static void method2(){
System.out.print("success!");
errorRequiredFieldMissing gui = new errorRequiredFieldMissing();
gui.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
gui.setSize(400,100);
gui.setLocation(300,25);
gui.setVisible(true);
}
}
try this way:
exit.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
exitActionPerformed(evt);
}
});
and then
private void exitActionPerformed(java.awt.event.ActionEvent evt) {
this.dispose();
}