java JavaFX TextArea 中的 Tab 键导航
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12860478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Tab key navigation in JavaFX TextArea
提问by nailujed
How do I make hitting the Tab Key in TextArea navigates to the next control ?
如何使点击 TextArea 中的 Tab 键导航到下一个控件?
I could add a listener to cath de key pressed event, but how do I make te TextArea control to lose it focus (without knowing the next field in the chain to be focused) ?
我可以为 cath de keypressed 事件添加一个侦听器,但是如何使 TextArea 控件失去焦点(不知道链中要聚焦的下一个字段)?
@FXML protected void handleTabKeyTextArea(KeyEvent event) {
if (event.getCode() == KeyCode.TAB) {
...
}
}
采纳答案by amru
This code traverse focus if pressing TAB and insert tab if pressing CONTROL+TAB
如果按 TAB 则此代码遍历焦点,如果按 CONTROL+TAB 则插入制表符
textArea.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
@Override
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.TAB) {
SkinBase skin = (SkinBase) textArea.getSkin();
if (skin.getBehavior() instanceof TextAreaBehavior) {
TextAreaBehavior behavior = (TextAreaBehavior) skin.getBehavior();
if (event.isControlDown()) {
behavior.callAction("InsertTab");
} else {
behavior.callAction("TraverseNext");
}
event.consume();
}
}
}
});
回答by Tom
I use the traverse-methods
我使用遍历方法
@Override
public void handle(KeyEvent event) {
if (event.getCode().equals(KeyCode.TAB)) {
Node node = (Node) event.getSource();
if (node instanceof TextField) {
TextFieldSkin skin = (TextFieldSkin) ((TextField)node).getSkin();
if (event.isShiftDown()) {
skin.getBehavior().traversePrevious();
}
else {
skin.getBehavior().traverseNext();
}
}
else if (node instanceof TextArea) {
TextAreaSkin skin = (TextAreaSkin) ((TextArea)node).getSkin();
if (event.isShiftDown()) {
skin.getBehavior().traversePrevious();
}
else {
skin.getBehavior().traverseNext();
}
}
event.consume();
}
}
回答by MarcG
As of Java 9 (2017), most answers in this page don't work, since you can't do skin.getBehavior()
anymore.
从 Java 9 (2017) 开始,此页面中的大多数答案都不起作用,因为您不能再这样做skin.getBehavior()
了。
This works:
这有效:
@Override
public void handle(KeyEvent event) {
KeyCode code = event.getCode();
if (code == KeyCode.TAB && !event.isShiftDown() && !event.isControlDown()) {
event.consume();
Node node = (Node) event.getSource();
try {
Robot robot = new Robot();
robot.keyPress(KeyCode.CONTROL.getCode());
robot.keyPress(KeyCode.TAB.getCode());
robot.delay(10);
robot.keyRelease(KeyCode.TAB.getCode());
robot.keyRelease(KeyCode.CONTROL.getCode());
}
catch (AWTException e) { }
}
}
This also works:
这也有效:
@Override
public void handle(KeyEvent event) {
KeyCode code = event.getCode();
if (code == KeyCode.TAB && !event.isShiftDown() && !event.isControlDown()) {
event.consume();
Node node = (Node) event.getSource();
KeyEvent newEvent
= new KeyEvent(event.getSource(),
event.getTarget(), event.getEventType(),
event.getCharacter(), event.getText(),
event.getCode(), event.isShiftDown(),
true, event.isAltDown(),
event.isMetaDown());
node.fireEvent(newEvent);
}
}
Both simulate pressing CTRL+TAB
when the user presses TAB
. The default behaviour of the TextArea for CTRL+TAB
is moving the focus to the next control. Please note the second code is based on Johan De Schutter's answer.
CTRL+TAB
当用户按下时,两者都模拟按下TAB
。TextArea 的默认行为CTRL+TAB
是将焦点移动到下一个控件。请注意,第二个代码基于 Johan De Schutter 的回答。
回答by Johan De Schutter
If a different solution for the Tab - Focus problem. The default behaviour of the TextArea for the CTRL+TAB key is a move of focus to the next control. So I replaced the TAB key event with a CTRL+TAB key event, and when the user hits CTRL+TAB a tab character is inserted in the TextArea.
如果选项卡 - 焦点问题的不同解决方案。CTRL+TAB 键的 TextArea 的默认行为是将焦点移动到下一个控件。所以我用 CTRL+TAB 键事件替换了 TAB 键事件,当用户点击 CTRL+TAB 时,一个制表符被插入到 TextArea 中。
My question: is it OK to fire an event in the event filter? And is it OK to replace the text of the KeyEvent with the FOCUS_EVENT_TEXT, in order to have an indication if it is the an event generated by the user, or from the event created in the event filter.
我的问题:可以在事件过滤器中触发事件吗?是否可以用 FOCUS_EVENT_TEXT 替换 KeyEvent 的文本,以便指示它是由用户生成的事件,还是来自事件过滤器中创建的事件。
The event filter:
事件过滤器:
javafx.scene.control.TextArea textArea1 = new javafx.scene.control.TextArea();
textArea1.addEventFilter(KeyEvent.KEY_PRESSED, new TextAreaTabToFocusEventHandler());
The event handler:
事件处理程序:
public class TextAreaTabToFocusEventHandler implements EventHandler<KeyEvent>
{
private static final String FOCUS_EVENT_TEXT = "TAB_TO_FOCUS_EVENT";
@Override
public void handle(final KeyEvent event)
{
if (!KeyCode.TAB.equals(event.getCode()))
{
return;
}
// handle events where the TAB key or TAB + CTRL key is pressed
// so don't handle the event if the ALT, SHIFT or any other modifier key is pressed
if (event.isAltDown() || event.isMetaDown() || event.isShiftDown())
{
return;
}
if (!(event.getSource() instanceof TextArea))
{
return;
}
final TextArea textArea = (TextArea) event.getSource();
if (event.isControlDown())
{
// if the event text contains the special focus event text
// => do not consume the event, and let the default behaviour (= move focus to the next control) happen.
//
// if the focus event text is not present, then the user has pressed CTRL + TAB key,
// then consume the event and insert or replace selection with tab character
if (!FOCUS_EVENT_TEXT.equalsIgnoreCase(event.getText()))
{
event.consume();
textArea.replaceSelection("\t");
}
}
else
{
// The default behaviour of the TextArea for the CTRL+TAB key is a move of focus to the next control.
// So we consume the TAB key event, and fire a new event with the CTRL + TAB key.
event.consume();
final KeyEvent tabControlEvent = new KeyEvent(event.getSource(), event.getTarget(), event.getEventType(), event.getCharacter(),
FOCUS_EVENT_TEXT, event.getCode(), event.isShiftDown(), true, event.isAltDown(), event.isMetaDown());
textArea.fireEvent(tabControlEvent);
}
}
}
回答by Alexandre
Inspired by the previous answers and for a very similar case, I built the following class:
受之前的答案和一个非常相似的案例的启发,我构建了以下类:
/**
* Handles tab/shift-tab keystrokes to navigate to other fields,
* ctrl-tab to insert a tab character in the text area.
*/
public class TabTraversalEventHandler implements EventHandler<KeyEvent> {
@Override
public void handle(KeyEvent event) {
if (event.getCode().equals(KeyCode.TAB)) {
Node node = (Node) event.getSource();
if (node instanceof TextArea) {
TextAreaSkin skin = (TextAreaSkin) ((TextArea)node).getSkin();
if (!event.isControlDown()) {
// Tab or shift-tab => navigational action
if (event.isShiftDown()) {
skin.getBehavior().traversePrevious();
} else {
skin.getBehavior().traverseNext();
}
} else {
// Ctrl-Tab => insert a tab character in the text area
TextArea textArea = (TextArea) node;
textArea.replaceSelection("\t");
}
event.consume();
}
}
}
}
I just have not seen the necessity of handling tab in the context of a TextField so I removed this part.
我只是没有看到在 TextField 上下文中处理选项卡的必要性,所以我删除了这部分。
Then this class can be very easily used as described by User:
然后这个类可以很容易地使用,如User 所述:
TextArea myTextArea = new TextArea();
mytTextArea.addEventFilter(KeyEvent.KEY_PRESSED, new TabTraversalEventHandler());
And the whole thing works like a charm :)
整个事情就像一个魅力:)
回答by Franz Deschler
I had the same issue and I like the traverse-methods that Tom uses. But I also want to insert a tab when ctrl+tab is pressed.
我有同样的问题,我喜欢汤姆使用的遍历方法。但我也想在按下 ctrl+tab 时插入一个选项卡。
The call
电话
behavior.callAction("InsertTab");
doesn′t work with JavaFX8. A look in the TextAreaBehaviour class showed me that there now is a "TraverseOrInsertTab" action.
不适用于 JavaFX8。看一下 TextAreaBehaviour 类,我发现现在有一个“TraverseOrInsertTab”动作。
But however, I think this kind of action calling is quite unstable across several java versions because it relies on a string that is passed.
但是,我认为这种动作调用在多个 Java 版本中非常不稳定,因为它依赖于传递的字符串。
So instead of the callAction() method, I used
因此,我使用了 callAction() 方法而不是
textArea.replaceSelection("\t");