Created
May 21, 2013 23:34
-
-
Save jewelsea/5624145 to your computer and use it in GitHub Desktop.
Allow a Tab key press in a TextArea to focus on the next field and an Enter key press in a TextArea to trigger a default button.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javafx.application.Application; | |
import static javafx.application.Application.launch; | |
import javafx.beans.value.*; | |
import javafx.collections.ObservableList; | |
import javafx.event.*; | |
import javafx.scene.*; | |
import javafx.scene.control.*; | |
import static javafx.scene.input.KeyCode.ENTER; | |
import static javafx.scene.input.KeyCode.TAB; | |
import javafx.scene.input.KeyEvent; | |
import javafx.scene.layout.VBox; | |
import javafx.stage.*; | |
public class TextAreaTabAndEnterHandler extends Application { | |
final Label status = new Label(); | |
public static void main(String[] args) { launch(args); } | |
@Override public void start(final Stage stage) { | |
final TextArea textArea1 = new TabAndEnterIgnoringTextArea(); | |
final TextArea textArea2 = new TabAndEnterIgnoringTextArea(); | |
final Button defaultButton = new Button("OK"); | |
defaultButton.setDefaultButton(true); | |
defaultButton.setOnAction(new EventHandler<ActionEvent>() { | |
@Override public void handle(ActionEvent event) { | |
status.setText("Default Button Pressed"); | |
} | |
}); | |
textArea1.textProperty().addListener(new ClearStatusListener()); | |
textArea2.textProperty().addListener(new ClearStatusListener()); | |
VBox layout = new VBox(10); | |
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;"); | |
layout.getChildren().setAll( | |
textArea1, | |
textArea2, | |
defaultButton, | |
status | |
); | |
stage.setScene( | |
new Scene(layout) | |
); | |
stage.show(); | |
} | |
class ClearStatusListener implements ChangeListener<String> { | |
@Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) { | |
status.setText(""); | |
} | |
} | |
class TabAndEnterIgnoringTextArea extends TextArea { | |
final TextArea myTextArea = this; | |
TabAndEnterIgnoringTextArea() { | |
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler()); | |
} | |
class TabAndEnterHandler implements EventHandler<KeyEvent> { | |
private KeyEvent recodedEvent; | |
@Override public void handle(KeyEvent event) { | |
if (recodedEvent != null) { | |
recodedEvent = null; | |
return; | |
} | |
Parent parent = myTextArea.getParent(); | |
if (parent != null) { | |
switch (event.getCode()) { | |
case ENTER: | |
if (event.isControlDown()) { | |
recodedEvent = recodeWithoutControlDown(event); | |
myTextArea.fireEvent(recodedEvent); | |
} else { | |
Event parentEvent = event.copyFor(parent, parent); | |
myTextArea.getParent().fireEvent(parentEvent); | |
} | |
event.consume(); | |
break; | |
case TAB: | |
if (event.isControlDown()) { | |
recodedEvent = recodeWithoutControlDown(event); | |
myTextArea.fireEvent(recodedEvent); | |
} else { | |
ObservableList<Node> children = parent.getChildrenUnmodifiable(); | |
int idx = children.indexOf(myTextArea); | |
if (idx >= 0) { | |
for (int i = idx + 1; i < children.size(); i++) { | |
if (children.get(i).isFocusTraversable()) { | |
children.get(i).requestFocus(); | |
break; | |
} | |
} | |
for (int i = 0; i < idx; i++) { | |
if (children.get(i).isFocusTraversable()) { | |
children.get(i).requestFocus(); | |
break; | |
} | |
} | |
} | |
} | |
event.consume(); | |
break; | |
} | |
} | |
} | |
private KeyEvent recodeWithoutControlDown(KeyEvent event) { | |
return new KeyEvent( | |
event.getEventType(), | |
event.getCharacter(), | |
event.getText(), | |
event.getCode(), | |
event.isShiftDown(), | |
false, | |
event.isAltDown(), | |
event.isMetaDown() | |
); | |
} | |
} | |
} | |
} |
Thanks for sharing your code. It inspired me to improve on your work.
Your solution doesn't work in most scenarios. For example, I have a TextArea and a Label inside a HBox, and your code will only search for nodes within that HBox, it does not attempt to look for siblings of the HBox.
I have created my own Gist which searches the Node graph in a more complete manner.
https://gist.github.com/nickthecoder/57ac20829214f1209e41e851d955ed35
My Gist concentrates only on the "focus next" part, not on the keyboard event filters in you solution.
Sorry, it is written in Kotlin, not Java, but I think it will be easy to port to Java.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Solution to StackOverflow question: JavaFX 2 TextArea: How to stop it from consuming [Enter] and [Tab]