如何在 TextArea 上使用 TAB/Enter KeyPressed,并在不使用内部 API 的情况下替换为 focustraversal 或输入键?
How to consume a TAB/Enter KeyPressed on the TextArea, and replace with focustraversal or enter key without using internal API?
我需要一个可以自动换行、添加滚动条等的控件 - 但忽略回车键并使用 tab/shift 选项卡跳转到下一个控件。我似乎无法理解这一点。
这是我做过的控件,貌似只是简单的停留在文本区域。 (这是从一个旧的在线示例中使用的,它似乎只有在 textArea 与其余部分位于同一节点时才有效)。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public TabAndEnterIgnoringTextArea() {
this.setWrapText(true);
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler());
}
private class TabAndEnterHandler implements EventHandler<KeyEvent> {
private KeyEvent recodedEvent;
@Override
public void handle(KeyEvent event) {
if (recodedEvent != null) {
recodedEvent = null;
return;
}
Parent parent = 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 if (event.isShiftDown()) {
ObservableList<Node> children = FXCollections.observableArrayList();
addAllDescendents(parent, children);
int idx = children.indexOf(myTextArea);
if (idx > 0) {
for (int i = idx - 1; i > 0; i--) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
}
} else {
ObservableList<Node> children = FXCollections.observableArrayList();
addAllDescendents(parent, children);
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;
}
}
if (idx + 1 >= children.size()) {
for (int i = 0; i < idx; i++) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
}
}
}
event.consume();
break;
default:
break;
}
}
}
private void addAllDescendents(Parent parent, ObservableList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
nodes.add(node);
if (node instanceof Parent)
addAllDescendents((Parent) node, nodes);
}
}
private KeyEvent recodeWithoutControlDown(KeyEvent event) {
return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(),
event.isShiftDown(), false, event.isAltDown(), event.isMetaDown());
}
}
一旦我进入我的领域,它就不会随键盘离开。有任何想法吗?另外 - 我不应该假设下一个控件实际上在我父级的节点中,因为该控件可能是另一个控件的一部分,其中它的最后一个控件和下一个控件可能在上面的父级上。
基本上我想要场景图中的下一个可着陆项目。
我可以使用内部 API - 但我知道这是非常令人沮丧的。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public 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();
Scene scene = parent.getScene();
while (scene == null){
parent = parent.getParent();
scene = parent.getScene();
}
SceneTraversalEngine engine = new SceneTraversalEngine(getScene());
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.isShiftDown()){
engine.trav(myTextArea, Direction.PREVIOUS);
}else {
engine.trav(myTextArea, Direction.NEXT);
}
}
}
}
private KeyEvent recodeWithoutControlDown(KeyEvent event) {
return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(),
event.isShiftDown(), false, event.isAltDown(), event.isMetaDown());
}
}
}
谢谢
我想我找到了一个解决方案,可以让我按照设计完成这项工作。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public TabAndEnterIgnoringTextArea() {
this.setWrapText(true);
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler());
}
private class TabAndEnterHandler implements EventHandler<KeyEvent> {
@Override
public void handle(KeyEvent event) {
if(event.getCode() == KeyCode.TAB || event.getCode() == KeyCode.ENTER) {
event.consume();
if(event.getCode() == KeyCode.TAB){
selectNextNode(!event.isShiftDown());
}
}
}
private void selectNextNode(boolean forward){
List<Node> nodes = getAllNodes(myTextArea.getScene().getRoot());
int index = nodes.indexOf(myTextArea);
if(forward){
if(index < nodes.size() - 1) {
nodes.get(index + 1).requestFocus();
}else {
nodes.get(0).requestFocus();
}
}else {
if(index == 0) {
nodes.get(nodes.size() - 1).requestFocus();
}else {
nodes.get(index - 1).requestFocus();
}
}
}
private ArrayList<Node> getAllNodes(Parent root) {
ArrayList<Node> nodes = new ArrayList<Node>();
addAllDescendents(root, nodes);
return nodes;
}
private void addAllDescendents(Parent parent, ArrayList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
if(node.isFocusTraversable()){
nodes.add(node);
}
if (node instanceof Parent)
addAllDescendents((Parent)node, nodes);
}
}
}
}
如果您发现此方法有任何问题,我将不胜感激,但它似乎适合我的目的。
我需要一个可以自动换行、添加滚动条等的控件 - 但忽略回车键并使用 tab/shift 选项卡跳转到下一个控件。我似乎无法理解这一点。
这是我做过的控件,貌似只是简单的停留在文本区域。 (这是从一个旧的在线示例中使用的,它似乎只有在 textArea 与其余部分位于同一节点时才有效)。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public TabAndEnterIgnoringTextArea() {
this.setWrapText(true);
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler());
}
private class TabAndEnterHandler implements EventHandler<KeyEvent> {
private KeyEvent recodedEvent;
@Override
public void handle(KeyEvent event) {
if (recodedEvent != null) {
recodedEvent = null;
return;
}
Parent parent = 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 if (event.isShiftDown()) {
ObservableList<Node> children = FXCollections.observableArrayList();
addAllDescendents(parent, children);
int idx = children.indexOf(myTextArea);
if (idx > 0) {
for (int i = idx - 1; i > 0; i--) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
}
} else {
ObservableList<Node> children = FXCollections.observableArrayList();
addAllDescendents(parent, children);
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;
}
}
if (idx + 1 >= children.size()) {
for (int i = 0; i < idx; i++) {
if (children.get(i).isFocusTraversable()) {
children.get(i).requestFocus();
break;
}
}
}
}
}
event.consume();
break;
default:
break;
}
}
}
private void addAllDescendents(Parent parent, ObservableList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
nodes.add(node);
if (node instanceof Parent)
addAllDescendents((Parent) node, nodes);
}
}
private KeyEvent recodeWithoutControlDown(KeyEvent event) {
return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(),
event.isShiftDown(), false, event.isAltDown(), event.isMetaDown());
}
}
一旦我进入我的领域,它就不会随键盘离开。有任何想法吗?另外 - 我不应该假设下一个控件实际上在我父级的节点中,因为该控件可能是另一个控件的一部分,其中它的最后一个控件和下一个控件可能在上面的父级上。
基本上我想要场景图中的下一个可着陆项目。
我可以使用内部 API - 但我知道这是非常令人沮丧的。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public 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();
Scene scene = parent.getScene();
while (scene == null){
parent = parent.getParent();
scene = parent.getScene();
}
SceneTraversalEngine engine = new SceneTraversalEngine(getScene());
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.isShiftDown()){
engine.trav(myTextArea, Direction.PREVIOUS);
}else {
engine.trav(myTextArea, Direction.NEXT);
}
}
}
}
private KeyEvent recodeWithoutControlDown(KeyEvent event) {
return new KeyEvent(event.getEventType(), event.getCharacter(), event.getText(), event.getCode(),
event.isShiftDown(), false, event.isAltDown(), event.isMetaDown());
}
}
}
谢谢
我想我找到了一个解决方案,可以让我按照设计完成这项工作。
public class TabAndEnterIgnoringTextArea extends TextArea {
final TextArea myTextArea = this;
public TabAndEnterIgnoringTextArea() {
this.setWrapText(true);
addEventFilter(KeyEvent.KEY_PRESSED, new TabAndEnterHandler());
}
private class TabAndEnterHandler implements EventHandler<KeyEvent> {
@Override
public void handle(KeyEvent event) {
if(event.getCode() == KeyCode.TAB || event.getCode() == KeyCode.ENTER) {
event.consume();
if(event.getCode() == KeyCode.TAB){
selectNextNode(!event.isShiftDown());
}
}
}
private void selectNextNode(boolean forward){
List<Node> nodes = getAllNodes(myTextArea.getScene().getRoot());
int index = nodes.indexOf(myTextArea);
if(forward){
if(index < nodes.size() - 1) {
nodes.get(index + 1).requestFocus();
}else {
nodes.get(0).requestFocus();
}
}else {
if(index == 0) {
nodes.get(nodes.size() - 1).requestFocus();
}else {
nodes.get(index - 1).requestFocus();
}
}
}
private ArrayList<Node> getAllNodes(Parent root) {
ArrayList<Node> nodes = new ArrayList<Node>();
addAllDescendents(root, nodes);
return nodes;
}
private void addAllDescendents(Parent parent, ArrayList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
if(node.isFocusTraversable()){
nodes.add(node);
}
if (node instanceof Parent)
addAllDescendents((Parent)node, nodes);
}
}
}
}
如果您发现此方法有任何问题,我将不胜感激,但它似乎适合我的目的。