Two Eventhandler for same Key - java

I have a JavaFX Scene with with a login form and a register form which slide into the scene from the outside. The main anchorpane is root and the other two are login_form and register_form. Each form has one button - login which is calling login() and register which is callling register().
login_trigger and register_trigger are two buttons which let the forms slide in. When the login form slides in, I should be able to open login() when I press Enter. The same for the register form.
That's what I have thought, but whenever I press Enter, nothing happens. It is working without a problem with the buttons but not with Enter. I would like to have the Eventhandler set to the form which is displayed.
I thought it would work when I set the EventHandler to null, when the form is closing and to give it a value when it's opening. Is there another way to do it or do I have just a stupid mistake in my code?
login_trigger.setOnAction(e -> {
if (login_form.getTranslateX() != 0) {
openLogin.play();
login.setOnKeyPressed(e2 -> {
if (e2.getCode() == KeyCode.ENTER) {
login();
}
});
if (register_form.getTranslateX() != 1280) {
closeRegister.setToX(1280);
closeRegister.play();
}
} else {
login.setOnKeyPressed(null);
closeLogin.setToX(-250);
closeLogin.play();
}
});
register_trigger.setOnAction(e -> {
if (register_form.getTranslateX() != 1030) {
openRegister.play();
register.setOnKeyPressed(e2 -> {
if (e2.getCode() == KeyCode.ENTER) {
register();
}
});
if (login_form.getTranslateX() != -250) {
closeLogin.setToX(-250);
closeLogin.play();
}
} else {
register.setOnKeyPressed(null);
closeRegister.setToX(1280);
closeRegister.play();
}
});

Related

Updating the page view after closing the modal window (Vaadin 8)

I use Vaadin version 8.9.3. I need to show a modal window when I click a button. In this window, the user enters the information, clicks on the button, the information is saved and displayed in a table in the main window.
Main page:
Modal page:
To display the modal window I use BrowserWindowOpener. In order not to overload the question, I will give only a small piece of code. The FormLayout in which there is TextField("uid"), Grid and Button("Создать") - DeviceForm:
private BrowserWindowOpener opener = new BrowserWindowOpener(ButtlonClickUI.class);
private DeviceConfigsService configsService = DeviceConfigsService.getInstance();
private Grid<DeviceConfigs> grid = new Grid<>(DeviceConfigs.class);
public DeviceForm(MyUI myUI, Devices device) {
opener.extend(button);
opener.setFeatures("resizable");
configsService.setDevice(device);
configsService.addSaveEventListener(new OnSaveEventListener() {
#Override
public void SaveEvent() {
updateList();
}
});
grid.setColumns(NAME_COLUMN, VERSION_COLUMN, STATE_COLUMN);
grid.getColumn(NAME_COLUMN).setCaption(NAME_COLUMN_NAME).setExpandRatio(1);
grid.getColumn(STATE_COLUMN).setCaption(STATE_COLUMN_NAME).setExpandRatio(1);
grid.getColumn(VERSION_COLUMN).setCaption(VERSION_COLUMN_NAME).setExpandRatio(1);
updateList();
}
public void updateList() {
List<DeviceConfigs> configs = configsService.findAll();
if(configs.size() == 0) {
delete.setVisible(false);
}
grid.setItems(configs);
}
Here, config service is a service that allows you to save, delete and find the information displayed in the grid (DeviceConfigs), in this case, it does not matter which one. OnSaveEventListener is the listener I created, called when the save method in configsService is called:
public synchronized void save(DeviceConfigs entry) {
if(entry == null) {
LOGGER.log(Level.SEVERE,
"DeviceConfigs is null");
return;
}
if(entry.getName() == null || entry.getName().isEmpty()) {
LOGGER.log(Level.SEVERE,
"DeviceConfigs name is null");
}
try {
entry = (DeviceConfigs) entry.clone();
} catch (Exception e) {
throw new RuntimeException(e);
}
device.putConfig(entry);
if(listener != null) { listener.SaveEvent(); }
}
UI that is called in opener:
public class ButtlonClickUI extends UI {
private DeviceConfigsService configsService = DeviceConfigsService.getInstance();
private Button close = new Button("close", VaadinIcons.CLOSE);
#Override
protected void init(VaadinRequest request) {
VerticalLayout layout = new VerticalLayout();
layout.addComponent(close);
...
close.addClickListener(event ->{
configsService.save(new DeviceConfigs(requestStr.getValue(), true, typeOfClick.getValue()));
closeThis();
});
}
private void closeThis() {
JavaScript.eval("close()");
// Detach the UI from the session
getUI().close();
}
}
The problem is this - I couldn't think of a better way to track the event of writing new data and closing the modal window to update the values of the table until I got to creating a listener.
But now, after clicking the Close button in the modal window, it closes, the data is updated but not displayed until I interact with some element on the main page (by trial and error, I got to the point where the components on the main page will not update their visibility until the modal window closes and the main page returns focus).
But I can't think of any way to automatically update the table values in the main menu when the modal window is closed.
Any possible solution to the problem, please.

javafx: How to bind the Enter key to a button and fire off an event when it is clicked?

Basically, I have a okayButton that sits in a stage and when it is clicked , it performs a list of tasks. Now I want to bind the Enter key to this button such that when it is clicked OR the ENTER key is pressed, it performs a list of tasks.
okayButton.setOnAction(e -> {
.........
}
});
How can I do that ? I have read the following post already. However, it did not help me to achieve what I want to do.
First, set a hanlder on your button :
okayButton.setOnAction(e -> {
......
});
If the button has the focus, pressing Enter will automatically call this handler. Otherwise, you can do this in your start method :
#Override
public void start(Stage primaryStage) {
// ...
Node root = ...;
setGlobalEventHandler(root);
Scene scene = new Scene(root, 0, 0);
primaryStage.setScene(scene);
primaryStage.show();
}
private void setGlobalEventHandler(Node root) {
root.addEventHandler(KeyEvent.KEY_PRESSED, ev -> {
if (ev.getCode() == KeyCode.ENTER) {
okayButton.fire();
ev.consume();
}
});
}
If you have only one button of this kind, you can use the following method instead.
okayButton.setDefaultButton(true);
You can dynamically change the default button property of the currently focused button by using binding
btn.defaultButtonProperty().bind(btn.focusedProperty());
I've had the same problem like mynameisJEFF. (I'm using Windows and as I read here: http://mail.openjdk.java.net/pipermail/openjfx-dev/2016-June/019234.html it is the SPACE_BAR and not ENTER, which fires a Button in JavaFX) I didn't want to add a listener to every Button, so I registered a Listener to the root node and asked the scene, which node is focused to fire that one. Here is my code (it is xtend, but I think it very easy to understand):
override start(Stage primaryStage) throws Exception {
val root = FXTable.createRoot
val mainScene = new Scene(root)
root.addEventHandler(KeyEvent.KEY_RELEASED, [event|
if(event.code === KeyCode.ENTER){
switch(focusedNode : mainScene.focusOwnerProperty.get){
Button:{
focusedNode.fire
event.consume
}
default:{
}
}
}
])
primaryStage.scene = mainScene
primaryStage.show
primaryStage.maximized = true
}
There is a much more simple a standard way to do that using setOnKeyPressed
okayButton.setOnKeyPressed(event -> {
if (event.getCode().equals(KeyCode.ENTER)) {
okayButton.fire();
}
}
);
And don't forget that you should define SetOnAction too, other way it's work but it's doing nothing.
okayButton.setOnAction(event -> {
// Do what ever you want to your button do. Like :
System.Out.Print("Okay Button Fired (Clicked or Pressed");
}
);
This should work:
okayButton.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
if(evt.getKeyCode() == KeyEvent.VK_ENTER){
System.out.print("Your function call or code can go here");
}
}
});

Fire Button's onAction with Enter in JavaFX

I'm a newbie to JavaFx. In my JavaFX application I have set onAction property and it works fine when I press the button using mouse. I want to fire the same even when user press Enter on button. I know I can use a even handler to do that.
But when I read the onAction JavaDoc it says that this event get fire by a key press.
Property description:
The button's action, which is invoked whenever
the button is fired. This may be due to the user clicking on the
button with the mouse, or by a touch event, or by a key press, or if
the developer programmatically invokes the fire() method.
But when I press Enter key nothing happens. Is it error in documentation? Are there any other way to achieve that without adding alistener to the button?
P.S
After the comments I checked with space key then it get fired. But I want to set that to Enter key.
I have many buttons. I tried button.setDefaultButton(true); but it is not get fired. I think that is becacuse there are more than one button. If I set it just to a single button it works fine. How to set that to multiple buttons?
You can dynamically change the default button property of the currently focused button by using binding
btn.defaultButtonProperty().bind(btn.focusedProperty());
If you want to apply this to every Button in your program you can subclass the JavaFX-Button and bind this in the constructor. In your fxml-File you'll need to include your custom Button.
I wrote the following subclass:
public class FocusedButton extends javafx.scene.control.Button {
public FocusedButton ( ) {
super ( );
bindFocusToDefault ( );
}
public FocusedButton ( String text ) {
super ( text );
bindFocusToDefault ( );
}
public FocusedButton ( String text, Node graphic ) {
super ( text, graphic );
bindFocusToDefault ( );
}
private void bindFocusToDefault ( ) {
defaultButtonProperty().bind(focusedProperty());
}
}
To use this Code you will need to include your custom class in the fxml-File:
<?import your-package.*?>
If you want to use the Scene Builder things get a little bit more difficult: You'll need to export your custom Button in a jar-file and add this to Scene Builder as described here
To override the Enter key press behavior I use the function below calling it in the scene's key press event filter:
public static void overrideEnterKeyPressEvent(KeyEvent evt) {
EventTarget eventTarget = evt.getTarget();
if ((eventTarget instanceof TextArea) || (eventTarget instanceof TableView)) {
return;
}
if (eventTarget instanceof Button) {
Platform.runLater(() -> {
KeyEvent newEventPressed = new KeyEvent(KeyEvent.KEY_PRESSED, " ", " ", KeyCode.SPACE, false, false, false, false);
Event.fireEvent(eventTarget, newEventPressed);
KeyEvent newEventReleased = new KeyEvent(KeyEvent.KEY_RELEASED, " ", " ", KeyCode.SPACE, false, false, false, false);
Event.fireEvent(eventTarget, newEventReleased);
});
evt.consume();
return;
}
Platform.runLater(() -> {
KeyEvent tabEvent = new KeyEvent(KeyEvent.KEY_PRESSED, "", "\t", KeyCode.TAB, evt.isShiftDown(), false, false, false);
Event.fireEvent(eventTarget, tabEvent);
});
evt.consume();
}
Based on the event's target the function works as follows. For a TextArea or TableView, it's a NoOp. For a button, it consumes the Enter press event and fires Space key press and release events. And for all the other controls, it also consumes the Enter press event and fires a Tab event so pressing Enter moves focus to the next control just like Tab.
Then you just register an event filter for the whole scene:
scene.addEventFilter(KeyEvent.KEY_PRESSED, this::onSceneKeyPressedFilter);
And the event filter looks like:
private void onSceneKeyPressedFilter(KeyEvent evt) {
switch (evt.getCode()) {
case ENTER:
if (evt.isControlDown() && FxTools.isAncestorNodeTargeted(evt.getTarget(), fxHBoxInputAp)) {
return; //let the events for the fxHBoxInputAp pane pass through
}
overrideEnterKeyPressEvent(evt);
break;
...
default:
break;
}
}
----- edit because I forgot to include the isAncestorNodeTargeted() function; thanks for the comment, Robert -----
public static boolean isDescendantOf(Node node, Node ancestor) {
while ((node != null) && (node != ancestor)) {
node = node.getParent();
}
return (node != null);
}
public static boolean isAncestorNodeTargeted(EventTarget target, Node ancestor) {
return (target instanceof Node) ? isDescendantOf((Node) target, ancestor) : false;
}

JavaFX: How to make enter key submit TextArea

Sorry if this seems a little too easy, I'm brand new to JavaFX, this is my first little app built with it.
I am trying to make a bare bones chat client. I am using the JavaFX Scene builder to make the client UI, and a controller class connected to the FXML.
How can I make is so that the current text of in the text area is submitted to the server and the text area is cleared upon the enter key press, instead of using some kind of "send" button?
EDIT: Here is the code that is not working:
//...
public class FXMLDocumentController
{
//...
#FXML private TextArea messageBox;
//...
messageBox.setOnKeyPressed(new EventHandler<KeyEvent>()
{
#Override
public void handle(KeyEvent keyEvent)
{
if(keyEvent.getCode() == KeyCode.ENTER)
{
//sendMessage();
}
}
});
//...
This should get you what you want:
TextArea area;
//... (initialize all your JavaFX objects here...)
// wherever you assign event handlers...
area.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
String text = area.getText();
// do your thing...
// clear text
area.setText("");
}
}
});
I might add, that if you are so inclined to provide both a button and an enter key event, you could tie the event handler functions of both controls to a single common function in a way such as this:
Button sendButton;
TextArea area;
// init...
// set handlers
sendButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
sendFunction();
}
});
area.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent keyEvent) {
if (keyEvent.getCode() == KeyCode.ENTER) {
sendFunction();
}
}
});
// define send function
public void sendFunction() {
String text = this.area.getText();
// do the send stuff
// clear text (you may or may not want to do this here)
this.area.setText("");
}
Either way works, good luck.
You can use lambda expressions also ... I think it is more elegant and simply
textArea.setOnKeyPressed(event -> {
if(event.getCode() == KeyCode.ENTER){
//type here what you want
}
});
In addition to the other answers, I think it might be useful in some applications to not actually invoke the send function if the user pressed SHIFT+ENTER. In that case he/she maybe actually wanted a new line.
textArea.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
event.consume(); // otherwise a new line will be added to the textArea after the sendFunction() call
if (event.isShiftDown()) {
textArea.appendText(System.getProperty("line.separator"));
} else {
sendFunction();
}
}
});
If you don't want to send empty messages you can do something like this:
textArea.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
event.consume();
if (event.isShiftDown()) {
textArea.appendText(System.getProperty("line.separator"));
} else {
if(!textArea.getText().isEmpty()){
sendFunction();
}
}
}
});

Fake actionEvent doesn't dispose window. (Password dialog box)

I am using JOptionPane confirm dialog for password entry, it has OK and Cancel buttons and when I am using a while loop to detect when correct password has been entered, when user presses Cancel or "X", I trigger fake actionEvent to dispose window using this.dispose(); but for some weird reason it doesn't work and window opens regardless.
Here is the code:
while(identifier<1) {
if(action == 0) {
if(Arrays.equals(password.getPassword(),pass)) {
break;
} else {
actionPerformed(new ActionEvent(2,-1,""));
break;
}
} else {
actionPerformed(new ActionEvent(2,-1,"");
break;
}
}
And here is the part from actionPerformed method which should close the window:
if(e.getSource()==2) {
this.dispose();
}

Categories