I want to bind actions of JavaFX buttons to keyboard keys.
I want the following functionality:
When I click 1, the action for "Select one file" should trigger
When I click 9, the action for "Select multi file" should trigger
When I click Enter, the action for "OK" button should trigger
When I click Esc, the action for "Cancel" button should trigger
Todo this you could use EventFilters
If you want to have have it triggered only when one key is pressed:
addEventFilter(KeyEvent.KEY_PRESSED, event ->
{
if(event.getCode().equals(KeyCode.DIGIT1))
{
System.out.println("1 Pressed");
//Then either call the method directly
selectOneFile();
//Or fire the button
selectOneFileBtn.fire();
}
});
But as #ItachiUchiha (and I) recommend, you should use a combination of keys:
addEventFilter(KeyEvent.KEY_PRESSED, event ->
{
if(event.isAltDown() && event.getCode().equals(KeyCode.DIGIT1))
{
System.out.println("Alt + 1 Pressed");
//Then again, either call the method directly
selectOneFile();
//Or fire the button
selectOneFileBtn.fire();
}
});
Related
Why does the JavaFX alert dialog fires the Platform.exit(); when I press the Enter key even though the focused button in the alert dialog is Cancel?
soaStage.setOnCloseRequest(new EventHandler<WindowEvent>()
{
#Override
public void handle(WindowEvent event)
{
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm");
alert.setHeaderText("Are you sure you want to exit?");
alert.setContentText("Press OK to exit, or Cancel to stay.");
alert.initOwner(soaStage);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK)
{
Platform.exit();
}
else
{
event.consume();
}
}
});
Default buttons are fired on enter
The OK button is fired when you press enter because it is a default button.
A default Button is the button that receives a keyboard VK_ENTER press, if no other node in the scene consumes it.
In the default JavaFX 8 Modena stylesheet, the default button is indicated by being a blue color rather than than the gray color of a standard button.
How to remove default button behaviour
You can remove this behavior from the alert dialog by not making the OK button a default button:
Button okButton = (Button) alert.getDialogPane().lookupButton(ButtonType.OK);
okButton.setDefaultButton(false);
I advise you not to do this, but instead to always leave a default button in alert dialogs.
On OS X, standard alert type dialogs have a default button which is triggered by enter even if another button is focused, so the standard behavior in JavaFX is consistent with that. Note: to allow this behavior in default dialogs in OS X it is necessary to enable full keyboard access.
If you do change the OK button to not be a default button, I suggest you change its text to something else (e.g. Exit for your case):
okButton.setText("Exit");
How to make enter fire focused buttons
Now, if you also want to make it so that the focused button fires when you press enter, then you can do this:
EventHandler<KeyEvent> fireOnEnter = event -> {
if (KeyCode.ENTER.equals(event.getCode())
&& event.getTarget() instanceof Button) {
((Button) event.getTarget()).fire();
}
};
DialogPane dialogPane = alert.getDialogPane();
dialogPane.getButtonTypes().stream()
.map(dialogPane::lookupButton)
.forEach(button ->
button.addEventHandler(
KeyEvent.KEY_PRESSED,
fireOnEnter
)
);
Note: In any case, focused buttons are always fired when you press space.
We can add ENTER binding to the whole buttons by creating a class that need to be instantiated once when the application starts.
public class EnableButtonEnterKey extends ButtonBehavior<Button> {
public EnableButtonEnterKey() {
super(new Button());
BUTTON_BINDINGS.add(new KeyBinding(ENTER, KEY_PRESSED, "Press"));
BUTTON_BINDINGS.add(new KeyBinding(ENTER, KEY_RELEASED, "Release"));
}
}
When starting the application, call
new EnableButtonEnterKey();
That's it.
I have a SplitMenuButton, and I can't seem to find a way to trigger an event when the user clicks the arrow next to the button.
I would like to select item from dropdown(when mouse clicked on that item), display that in splitmenubutton and store value of that item in string to send to database.
I am not sure which event can do that, and I can not find any info on this either.
You can do something like.
for (final MenuItem item : smb.getItems()) {
item.setOnAction((event) -> {
System.out.println("Selected!");
});
}
I took the JQuery UI dialog form sample from JQuery UI website.
Since I wanted that, once the dialog is opened and the form is displayed, that pressing the key submits the form, I added the following in the onReady() :
$.extend($.ui.dialog.prototype.options, {
open: function() {
var $this = $(this);
// focus first button and bind enter to it
$this.parent().find('.ui-dialog-buttonpane button:first').focus();
$this.keypress(function(e) {
if( e.keyCode == 13 ) {
$this.parent().find('.ui-dialog-buttonpane button:first').click();
return false;
}
});
}
});
This does perfectly the trick (I mean the click() is triggered when it has to), but the following occurs :
When the form is first submited through a press on the key, the submission is performed once.
If I reopen the dialog, and submit it again with a press on the key, the form is submitted twice.
If I reopen the dialog, and submit it again with a press on the key, the form is submitted three times, and so on...
This can be tested with the following fiddle :
http://jsfiddle.net/fWW2E/
Let me add that doing so by clicking on the dedicated "Submit" button works properly, this fails only when pressing the key is involved.
Any ideas ?
Thank you !
Because since you're assigning this on "open" and your buttons are "closing" the dialog.
When this gets called though:
$('something').dialog('close');
doesn't actually remove the element, it just hides it. So the next time you click to open up a "new" dialog, you're really just showing the first one again. However the "open" event is getting fired again every time it's opened, which is adding a new keypress handler onto it.
Here's the fiddle. I actually write out to the console an array of the current handlers on that element. You'll see everytime you open the dialog that there is another keypress handler.
DEMO
I'm a little confused as to why this isn't the default behaviour?
So, how do I detect the enter key being pressed on my button and fire the click event handler? (For example on a TextInput field there is an 'enter' event)
Thanks
EDIT: Ignore everything I posted before.
You can use the keyDown event on the spark button and create an event handler using KeyboardEvent.
<s:Button label="Submit" keyDown="enter_pressed(event)" id="submit" click="submit_clickHandler(event)"/>
protected function enter_pressed(event:KeyboardEvent):void {
if(event.charCode == Keyboard.ENTER){
submit.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
}
EDIT : rollbacked to original post, event will only be fired if button is selected anyways
The enter event is fired when users sets focus on the button and has nothing to do with the keyboard enter key. If I'm not mistaken, the default key for activating a button in Flash is spacebar. You could use enter by doing something like this :
myButton.addEventListener(KeyboardEvent.KEY_DOWN, onMyButtonKeyDown);
private function onMyButtonKeyDown(event:KeyboardEvent):void
{
//simulate click if enter pressed
if(event.keyCode == Keyboard.ENTER)
myButton.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
Rather than assign to every buttons with MouseEvent, I assign to AIR application with:
private function init():void {
this.addEventListener(MouseEvent.MOUSE_DOWN,mpressKey);
}
However, I only want the mouse_down to execute if it detect a "button" property instead of Demo0.WindowedApplicationSkin2.Group3.contentGroup.g4 (g4 is an id).
Don't rely on event.target to check if a button was clicked or not. The target property is set to the innermost item that was clicked on. When you click on a button, you're not always clicking on The Button; you might be clicking on the text field that displays the label, or the background image if any, or some other child skinning part etc - the target will be set to this inner item.
If you want to have a single click handler for all buttons and take appropriate action based on the button clicked, you can assign same function as handlers for each button and check the event.currentTarget property; when an event handler is invoked, currentTarget is set to the object with which that handler was registered.
btn1.addEventListener(MouseEvent.CLICK, clickHandler);
btn2.addEventListener(MouseEvent.CLICK, clickHandler);
btn3.addEventListener(MouseEvent.CLICK, clickHandler);
public function clickHandler(e:MouseEvent):void
{
if(e.currentTarget == btn1){
/* Handle btn1 here */
}
else if(e.currentTarget == btn2){
/* Handle btn1 here */
}
else if(e.currentTarget == btn3){
/* Handle btn1 here */
}
}
When you add a single mouse handler using airApp.addEventListener, the currentTarget will always be your airApp and thus you can't use it to act as a single function to handle them all.
Are you asking how to test to see if the target is a Button, or a particular button?
If it's a Button
if ( e.target is Button ) { ... }
or if it's a particular button
if ( e.target == myButton ) { ... }