sco*_*ttb 7 textarea event-handling javafx-2
我想使用JavaFX TextArea,就好像它就像一个多行的TextField.换句话说,当我按[Tab]时,我想循环到窗体上的下一个控件,当我按下[Enter]时,我希望Key.Event转到defaultButton控件(而不是被TextArea使用).
TextArea的默认行为是[Tab]插入TextArea并且[Enter]插入换行符.
我知道我需要使用EventFilters来获取我想要的行为,但是我弄错了.我不希望TextArea使用这些事件......我只是希望它让它们"顺利进行".
此处的解决方案显示两个文本区域和一个默认按钮.当用户按下Tab键时,焦点移动到下一个控制按钮.当用户按下回车键时,将触发默认按钮.
要实现此行为:
该代码使用Java 8中实现的功能,因此需要Java 8来执行它.

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()
);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
另一种解决方案是为TextArea实现自己的自定义外观,其中包括新的键处理行为.我相信这样的过程会比这里提出的解决方案更复杂.
更新
关于这个问题的原始解决方案,我真的不喜欢的一件事是,一旦使用了Tab或Enter键,就无法触发它们的默认处理.因此,我更新了解决方案,以便在按Tab或Enter时用户按住控制键时,将执行默认的Tab或Enter操作.此更新的逻辑允许用户通过按CTRL + Enter或CTRL + Tab将新行或制表符空间插入文本区域.
| 归档时间: |
|
| 查看次数: |
6971 次 |
| 最近记录: |