JavaFX 2 TextArea:如何阻止它消耗[Enter]和[Tab] [英] JavaFX 2 TextArea: How to stop it from consuming [Enter] and [Tab]

查看:180
本文介绍了JavaFX 2 TextArea:如何阻止它消耗[Enter]和[Tab]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用JavaFX TextArea,就像它完全像多行TextField一样。换句话说,当我按[Tab],我想循环到窗体上的下一个控件,当我按[Enter]时,我希望Key.Event进入defaultButton控件(而不是被TextArea消费)。

I want to use a JavaFX TextArea as though it were exactly like a multi-line TextField. In other words, when I press [Tab] I want to cycle to the next control on the form and when I press [Enter] I want the Key.Event to go to the defaultButton control (rather than be consumed by the TextArea).

TextArea的默认行为是[Tab]插入到TextArea中,[Enter]插入一个新行字符。

The default behavior for TextArea is that [Tab] gets inserted into the TextArea and [Enter] inserts a new-line character.

我知道我需要使用EventFilters来获取我想要的行为,但是我错了。我不希望TextArea消费这些事件...我只是希望它让他们正确的。

I know that I need to use EventFilters to get the behavior that I want, but I'm getting it all wrong. I don't want the TextArea to consume these events ... I just want it to let them "go right on by".

推荐答案

此处的解决方案显示两个文本区域和默认按钮。
当用户按Tab键时,焦点移动到下一个控件。
当用户按下回车键时,默认按钮被触发。

The solution here displays two text areas and a default button. When the user presses the tab key, the focus moves to the next control down. When the user presses the enter key, the default button is fired.

要实现此行为:


  1. 每个文本区域的输入键按下被捕获到事件过滤器中,复制并定向到文本区域的父节点(包含默认的OK按钮)。这将导致在表单上的任何位置按下输入时,默认的确定按钮被触发。原始的输入键按钮被消耗,因此它不会在文本区域的文本中添加新行。

  2. 每个文本区域的标签键按下都被过滤器和处理父母的焦点遍历列表以找到下一个可控焦距控件,并且为该控件请求焦点。原始标签键按下被消耗,因此它不会在文本区域的文本中添加新的标签间距。

代码利用Java 8中实现的功能,因此需要执行 Java 8

The code makes use of features implemented in Java 8, so Java 8 is required to execute it.

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()
        );
      }
    }
  }
}

替代解决方案是为TextArea实现自己的自定义皮肤,其中包括新的按键处理行为。我相信这个过程比这里提出的解决方案要复杂得多。

An alternate solution would be to implement your own customized skin for TextArea which includes new key handling behavior. I believe that such a process would be more complicated than the solution presented here.

更新

有一件事我不太了解我原来解决这个问题的方法是,一旦Tab或Enter键被消耗,就没有办法触发它们的默认处理。所以我更新了解决方案,如果用户在按Tab或Enter的同时按住控制键,将执行默认的Tab或Enter操作。此更新的逻辑允许用户通过按CTRL + Enter或CTRL + Tab在文本区域中插入新的行或制表符空格。

One thing I didn't really like about my original solution to this problem was that once the Tab or Enter key was consumed, there was no way to trigger their default processing. So I updated the solution such that if the user holds the control key down when pressing Tab or Enter, the default Tab or Enter operation will be performed. This updated logic allows the user to insert a new line or tab space into the text area by pressing CTRL+Enter or CTRL+Tab.

这篇关于JavaFX 2 TextArea:如何阻止它消耗[Enter]和[Tab]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆