I'm trying to catch an ESCAPE key press in a textfield.
I was expecting to put a simple event listener (or even an event filter) to the textfield. But nothing works.
It seems all key events are caught, except the ESCAPE key I 'm waiting for.
Can you provide any help please,
Thanks in advance
PS: the following bunch of code explains how I proceed.
public class KeyEventSample extends Application {
/**
* Constructor
*/
public KeyEventSample() {super();}
#Override
public void start(final Stage primaryStage) throws Exception {
final TextField textField = new TextField();
final TextArea textArea = new TextArea();
textField.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
if (e.getCode() == KeyCode.ESCAPE)
textArea.appendText("ESCAPE");
else if (e.getCode() == KeyCode.ENTER)
textArea.appendText("ENTER");
else
textArea.appendText("->"+e.getCode().toString());
});
final BorderPane borderPane = new BorderPane();
borderPane.setCenter(textField);
borderPane.setBottom(textArea);
final Scene scene = new Scene(borderPane, 300, 300);
primaryStage.setScene(scene);
primaryStage.show();
}
}
Related
I have a very simple task to accomplish. I just want to press any letter on a button, matches the key code, and move the focus to a text field. I wrote
a simple test code as shown. I have no problem to shift the focus. However,
I don't want the letter I press shows up in the text field. Seemingly a simple programming solution turns out to be not so simple.
I don't understand why the event consume method doesn't stop the event from propagating down the event chain and have the typed letter shown up at the text field.
It seems like after the requestFocus is called, the text field picks up the letter typed from the button. This happens on Mac. Any help will be greatly appreciated.
package testkeynavigation;
public class TestKeyNavigation extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
TextField txt1 = new TextField();
TextField txt2 = new TextField();
VBox vbox = new VBox();
vbox.getChildren().add(btn);
vbox.getChildren().add(txt1);
vbox.getChildren().add(txt2);
root.getChildren().add(vbox);
Scene scene = new Scene(root, 300, 250);
btn.setOnKeyPressed((KeyEvent e) ->{
if (e.getCode() == KeyCode.A) {
e.consume();
System.out.println("e.isConsumed: "+e.isConsumed());
txt2.requestFocus();
}
});
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
btn.requestFocus();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
There are three kinds of key event: KEY_PRESSED, KEY_TYPED, and KEY_RELEASED. In a key stroke, an event of each of these types is fired, in that order, to the UI node that has the keyboard focus at the time of the event.
A TextField has an internal listener for KEY_TYPED events; so if a KEY_TYPED event occurs when the text field has focus, a character is entered into the text field (or other actions occur, e.g. deleting characters or moving the caret, depending on the key).
In your code, you listen for the first one of these - KEY_PRESSED - to occur on the button. If the key press has a code of A, you consume that event (the KEY_PRESSED event) then transfer keyboard focus to the text field. At a slightly later moment, the user releases the key, and since the text field now has focus, a KEY_TYPED event is fired on the text field. Note that this is a new event, so it is not consumed, so the text fields reacts as though a character has been entered. Finally, a KEY_RELEASED event is fired on the text field.
You can see this in action if you add the debugging code:
txt2.addEventFilter(KeyEvent.ANY, e -> {
System.out.printf("Key event on text field: type=%s, code=%s, character=%s%n",
e.getEventType(), e.getCode(), e.getCharacter());
});
To fix the problem, just listen for the last event in the series of events: the key released event. Note that you don't need to consume the event.
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
StackPane root = new StackPane();
TextField txt1 = new TextField();
TextField txt2 = new TextField();
VBox vbox = new VBox();
vbox.getChildren().add(btn);
vbox.getChildren().add(txt1);
vbox.getChildren().add(txt2);
root.getChildren().add(vbox);
Scene scene = new Scene(root, 300, 250);
btn.setOnKeyReleased((KeyEvent e) ->{
if (e.getCode() == KeyCode.A) {
txt2.requestFocus();
}
});
txt2.addEventFilter(KeyEvent.ANY, e -> {
System.out.printf("Key event on text field: type=%s, code=%s, character=%s%n",
e.getEventType(), e.getCode(), e.getCharacter());
});
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
btn.requestFocus();
}
I want get data from Tab in Tabpane JavaFX
I have 2 Tab in Tabpane, And each Tab I have a TextArea, I want click Button will get data from 2 tab
Here's my code:
btnThem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
try {
i++;
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/fxml/tab.fxml"));
Parent parent = (Parent) fxmlLoader.load();
Tab tab = new Tab("Điểm " + i);
tab.setContent(parent);
tab.setClosable(true);
tabPane.getTabs().add(tab);
controllerTab = (ControllerTab) fxmlLoader.getController();
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
});
Your question is ambiguous but it seems you want to get data from each textArea in tab.To do this you should get nodes (children) from each tab and by using lookup() we confirm and we parse node to textArea.I tried to figure your scene and made this example to help you :
public class example extends Application {
TextArea textArea = new TextArea();
TextArea textArea1 = new TextArea();
Button button = new Button("button");
#Override
public void start(Stage primaryStage) {
Tab tab1 = new Tab("tab1");
Tab tab2 = new Tab("tab2");
tab1.setContent(textArea);
tab2.setContent(textArea1);
TabPane pane = new TabPane();
pane.getTabs().addAll(tab1, tab2);
Node node1 = tab1.getContent();
Node node2 = tab2.getContent();
button.setOnAction((ActionEvent event) -> {
if (node1.lookup("TextArea") != null && node2.lookup("TextArea") != null) {
TextArea area1 = (TextArea) node1.lookup("TextArea");
TextArea area2 = (TextArea) node2.lookup("TextArea");
System.out.println(area1.getText() + " " + area2.getText());
}
});
VBox root = new VBox();
root.setAlignment(Pos.TOP_RIGHT);
root.getChildren().add(pane);
root.getChildren().add(button);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
And you can see the result :
Hello ,tab1 Hello ,tab2
Deleting directory C:\Users\Electron\Documents\NetBeansProjects\Buttono\dist\run341573612
jfxsa-run:
BUILD SUCCESSFUL (total time: 22 seconds)
I have a PopOver with a TextField with a strange behavior, this PopOver it's owned by other TextField because when I type the word 'Fernández' all keys are processed by the internal TextField except when I type a stressed vowel like 'á' that it's collected by the external TextField.
PopOver owned by TextField
But when i show the same PopOver owned by a button works fine and the internal TextField receives the letter 'á'
PopOver owned by Button
I would appreciate any help to solve it.
EDIT: Here you can see an example code to show this.
public class PopOverTest extends Application {
#Override
public void start(Stage primaryStage) {
CustomTextField externo = new CustomTextField();
ImageView imgView = new ImageView(new Image("test/image.png"));
externo.setLeft(imgView);
CustomTextField interno = new CustomTextField();
PopOver popOver = new PopOver();
popOver.setContentNode(interno);
popOver.stArrowLocation(PopOver.ArrowLocation.TOP_LEFT);
imgView.setOnMouseClicked(e -> {
popOver.show(imgView);
});
StackPane root = new StackPane();
root.getChildren().add(externo);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
I found a solution for this.
Changing the external Textfield EventDispatcher and the problem is resolved
EventDispatcher dispatcher = externalTextField.getEventDispatcher();
then on focus of the internal TextField
externalTextField.setEventDispatcher(interntalTextField.getEventDispatcher());
and when lost focus restore the EventDispatcher
externalTextField.setEventDispatcher(dispatcher);
That's all folks!
I have a JavaFx application that loads a transparent stage with some text on it.
I want any click on the application to be completely ignored and the background application (if any) to receive that click.
My code at this stage is as follows:
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.show();
layout.setMouseTransparent(true);
mainText.setMouseTransparent(true);
}
I was not able to achieve the requirement. setMouseTransparent() just prevented the text from triggering events, it still captured the mouse clicks.
Is it possible to achieve this in JavaFx ? Even if it is a per-OS solution.
A way of doing this action in Windows is through user32.dll and Java Native Access (JNA). We used GetWindowLong to get the current configuration of the window and SetWindowLong to update the bit field that is controlling the ability of the window be transparent to the mouse.
Following is a working example that demonstrates this functionality:
#Override
public void start(final Stage primaryStage) {
primaryStage.setAlwaysOnTop(true);
final StackPane layout = new StackPane();
final Text mainText = new Text();
layout.getChildren().add(mainText);
mainText.setText("|||||||||||||||||||||||||||");
final Scene mainScene = new Scene(layout);
mainScene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setScene(mainScene);
primaryStage.setTitle(sTitle);
primaryStage.show();
sUser32.EnumWindows(
(hWnd, data) -> {
final byte[] windowText = new byte[512];
sUser32.GetWindowTextA(hWnd, windowText, 512);
final String wText = Native.toString(windowText);
if (!wText.isEmpty() && wText.equals(sTitle)) {
final int initialStyle = com.sun.jna.platform.win32.User32.INSTANCE.GetWindowLong(hWnd, WinUser.GWL_EXSTYLE);
com.sun.jna.platform.win32.User32.INSTANCE.SetWindowLong(hWnd, WinUser.GWL_EXSTYLE, initialStyle | WinUser.WS_EX_TRANSPARENT );
return false;
}
return true;
}, null);
}
I'm writing a program in netbeans with javaFX
The view has several buttons in it with some bad buttons(like bombs is minesweeper), I'm trying to freeze the program when a bad button is pushed but i don't find how to do it
thanks!
There are various solutions to your problem. 2 among them are simply ignoring the action event or disabling the buttons like this:
public class ButtonAction extends Application {
final BooleanProperty buttonActionProperty = new SimpleBooleanProperty();
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
CheckBox checkBox = new CheckBox( "Enabled");
checkBox.setSelected(true);
// solution 1: check if action is allowed and process it or not
buttonActionProperty.bind( checkBox.selectedProperty());
Button button = new Button( "Click Me");
button.setOnAction(e -> {
if( buttonActionProperty.get()) {
System.out.println( "Allowed, processing action");
} else {
System.out.println( "Not allowed, no action");
}
});
// solution 2: remove comments to activate the code
// button.disableProperty().bind(buttonActionProperty.not());
root.getChildren().addAll(checkBox, button);
primaryStage.setScene(new Scene(root, 600, 200));
primaryStage.show();
}
}
Add a ROOT typed event filter that consumes all kind of events (mouse, keyboard etc.)
btnThatHasHiddenMine.setOnAction(( ActionEvent event ) ->
{
System.out.println("Ohh no! You just stepped over the mine!");
getGameboardPane().addEventFilter( EventType.ROOT, Event::consume );
});
Add the filter to your GameboardPane only, since we don't want to freeze other part of the app.