我很难使用< code>onKeyPressed事件。我的应用程序中有一个< code>TextField,允许用户按下[ENTER]键来实现某项功能;然而,我也为场景指定了一个默认按钮。
虽然我可以在<code>文本字段</code>中成功触发按键所需的操作,但默认按钮的操作始终首先执行。当用户位于文本字段
中时,我需要完全为按键使用事件。
请参阅以下MCVE:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple UI
VBox root = new VBox(10);
root.setPadding(new Insets(10));
root.setAlignment(Pos.CENTER);
// TextField
TextField textField = new TextField();
// Capture the [ENTER] key
textField.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.ENTER) {
System.out.println("-> Enter");
event.consume();
}
});
// Buttons
Button btnCancel = new Button("Cancel");
btnCancel.setCancelButton(true);
btnCancel.setOnAction(e -> {
System.out.println("-> Cancel");
primaryStage.close();
});
Button btnSave = new Button("Save");
btnSave.setDefaultButton(true);
btnSave.setOnAction(e -> {
System.out.println("-> Save");
primaryStage.close();
});
ButtonBar buttonBar = new ButtonBar();
buttonBar.getButtons().addAll(btnCancel, btnSave);
root.getChildren().addAll(textField, buttonBar);
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Consume Event");
primaryStage.show();
}
}
所需的行为是能够在文本字段中
键入并按 Enter 键。输出应仅显示 -
但是,当前发生的情况是,该阶段以以下输出结束:
-> Save
-> Enter
我是否将< code>event.consume()
调用放在了错误的位置?我想保持默认按钮不变。
编辑:
这似乎只是JDK 10中的一个问题。我再次尝试使用JDK 1.8.161,它的行为符合预期。Java 10可能的bug?
已提交错误报告:查看错误报告
问题得到了回答(这是OP报告的一个错误,修复程序已获得批准,并将使其进入openjfx14):
但为什么会这样呢?
下面是一个例子:对于像F5这样的键,调度完全按照指定的方式发生:沿着场景图向下直到文本字段,然后向上直到加速器。输出是:
-> filter on parent: source: VBox target: TextField
-> filter on field source: TextField target: TextField
-> handler on field source: TextField target: TextField
-> onKeyPressed on field source: TextField target: TextField
-> handler on parent: source: VBox target: TextField
-> onKeyPressed on parent source: VBox target: TextField
in accelerator
此外,链中的任何处理程序都可以使用并停止进一步调度。
现在切换到 ENTER,看看调度链是如何变得严重混乱的,以至于在加速器之后,轮到特殊压制的处理程序作为最后一个。输出:
-> filter on parent: source: VBox target: TextField
-> filter on field source: TextField target: TextField
-> handler on field source: TextField target: TextField
action added: javafx.event.ActionEvent[source=TextField@53c9244[styleClass=text-input text-field]]
-> filter on parent: source: VBox target: VBox
-> handler on parent: source: VBox target: VBox
-> onKeyPressed on parent source: VBox target: VBox
in accelerator
-> onKeyPressed on field source: TextField target: TextField
消费可以在所有处理程序中完成(并且有效),除了字段上的特殊处理程序。
如果没有actionHandler使用keyEvent,问题的根源似乎是手动转发keyEvent(我怀疑转发代码来自InputMap引入之前,但...没有深入研究那个方向)
这个例子有点脏(*咳嗽-内部api,私有字段...)并修补了text Field的inputMap。这个想法是摆脱手动转发,让正常事件调度完成它的工作。控制正常调度的钩子是事件的消耗状态。补丁代码
似乎可以工作,正如调度日志记录的输出所看到的那样,现在与F5等普通键相同-但请注意:没有进行正式测试!
最后示例代码:
public class TextFieldActionHandler extends Application {
private TextField textField;
private KeyCode actor = KeyCode.ENTER;
// private KeyCode actor = KeyCode.F5;
private Parent createContent() {
textField = new TextField("just some text");
textField.skinProperty().addListener((src, ov, nv) -> {
replaceEnter(textField);
});
// only this here is in the bug report, with consume
// https://bugs.openjdk.java.net/browse/JDK-8207774
textField.addEventHandler(ActionEvent.ACTION, e -> {
System.out.println("action added: " + e);
// e.consume();
});
//everything else is digging around
textField.setOnKeyPressed(event -> {
logEvent("-> onKeyPressed on field ", event);
});
textField.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
logEvent("-> filter on field ", event);
});
textField.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
logEvent("-> handler on field ", event);
});
VBox pane = new VBox(10, textField);
pane.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
logEvent("-> handler on parent: ", e);
});
pane.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
logEvent("-> filter on parent: ", e);
});
//everything else is digging around
pane.setOnKeyPressed(event -> {
logEvent("-> onKeyPressed on parent ", event);
});
return pane;
}
private void logEvent(String message, KeyEvent event) {
logEvent(message, event, false);
}
private void logEvent(String message, KeyEvent event, boolean consume) {
if (event.getCode() == actor) {
System.out.println(message + " source: " + event.getSource().getClass().getSimpleName()
+ " target: " + event.getTarget().getClass().getSimpleName());
if (consume)
event.consume();
}
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(createContent());
scene.getAccelerators().put(KeyCombination.keyCombination(actor.getName()),
() -> System.out.println("in accelerator"));
stage.setScene(scene);
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
/**
* fishy code snippet from TextFieldBehaviour:
*
* https://bugs.openjdk.java.net/browse/JDK-8207774
* during fire, the actionEvent without target is copied - such that
* the check for being consumed of the original has no effect
*/
// @Override protected void fire(KeyEvent event) {
// TextField textField = getNode();
// EventHandler<ActionEvent> onAction = textField.getOnAction();
// ActionEvent actionEvent = new ActionEvent(textField, null);
//
// textField.commitValue();
// textField.fireEvent(actionEvent);
//
// if (onAction == null && !actionEvent.isConsumed()) {
// forwardToParent(event);
// }
// }
// dirty patching
protected void replaceEnter(TextField field) {
TextFieldBehavior behavior = (TextFieldBehavior) FXUtils.invokeGetFieldValue(
TextFieldSkin.class, field.getSkin(), "behavior");
InputMap<TextField> inputMap = behavior.getInputMap();
KeyBinding binding = new KeyBinding(KeyCode.ENTER);
KeyMapping keyMapping = new KeyMapping(binding, this::fire);
keyMapping.setAutoConsume(false);
// note: this fails prior to 9-ea-108
// due to https://bugs.openjdk.java.net/browse/JDK-8150636
inputMap.getMappings().remove(keyMapping);
inputMap.getMappings().add(keyMapping);
}
/**
* Copy from TextFieldBehaviour, changed to set the field as
* both source and target of the created ActionEvent.
*
* @param event
*/
protected void fire(KeyEvent event) {
EventHandler<ActionEvent> onAction = textField.getOnAction();
ActionEvent actionEvent = new ActionEvent(textField, textField);
textField.commitValue();
textField.fireEvent(actionEvent);
// remove the manual forwarding, instead consume the keyEvent if
// the action handler has consumed the actionEvent
// this way, the normal event dispatch can jump in with the normal
// sequence
if (onAction != null || actionEvent.isConsumed()) {
event.consume();
}
// original code
// if (onAction == null && !actionEvent.isConsumed()) {
//// forwardToParent(event);
// }
logEvent("in fire: " + event.isConsumed(), event);
}
protected void forwardToParent(KeyEvent event) {
if (textField.getParent() != null) {
textField.getParent().fireEvent(event);
}
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TextFieldActionHandler.class.getName());
}
正如文件所述:
Windows / Linux:当有焦点时,默认按钮接收回车键。当默认按钮没有焦点,并且焦点在另一个按钮控件上时,ENTER键的按下将被另一个非默认按钮接收。当焦点在用户界面的其他地方,而不是在任何按钮上时,如果指定了默认按钮,并且场景中没有其他节点首先使用它,则默认按钮将接收ENTER键的按下。
所以我相信这是一个错误。正如我在评论中所说,一种解决方法是检查TextField是否在befault按钮的setOnAction内具有焦点,并在那里消费事件,直到他们修复它。
我有一个按钮,可以设置一个动作,比如 如何从该按钮中删除此EventFilter?我尝试了方法,但应该是什么参数?
我正在使用Microsoft Visual C#2010 Express编写一个窗口窗体应用程序。我在写一个数独程序。我以前写过一次这个程序,并让它工作。由于硬盘故障,我丢失了源代码。我在表格上画了一个网格。我让鼠标事件工作了。我有重要的新闻活动要办。然后我在表单中添加了几个按钮,并让它们工作。但随后出现了一个问题。在我添加按钮并使其工作后,按键事件停止工作。为什么按钮事件和按键事件之间会发生冲突
浮动操作按钮 运行方式 过渡 大屏幕 浮动操作按钮 浮动操作按钮 浮动操作按钮适用于进阶的操作。它是漂浮在 UI 上的一个圆形图标,具有一些动态的效果,比如变形、弹出、位移等等。 浮动操作按钮有两种尺寸: 默认尺寸:适用于多数应用情况。 迷你尺寸:仅用于创建与其他屏幕元素视觉的连续性。 浮动操作按钮 迷你浮动操作按钮 浮动操作按钮应至少放在距手机边缘 16dp 或电脑/台式机边缘 24dp 的地方
我想在下面的文本框中捕捉enter键按下事件。为了更清楚地说明这一点,我使用了一个ng repeat来填充tbody。以下是HTML: 这是我的模块: 我正在使用资源填充表格,我的控制器代码是:
问题内容: 我想在下面的文本框中捕获Enter键按下事件。为了更清楚地说明,我使用a 来填充tbody。这是HTML: 这是我的模块: 我正在使用一种资源来填充表,而我的控制器代码是: 问题答案: 您需要添加,如下所示: Javascript : HTML :
问题内容: 问题: 在哪里可以找到带有十六进制颜色代码的默认样式xml? 我在寻找’buttonStyle’样式,其他默认样式会影响诸如TextViews,Buttons等方面(如果您不更改方面的样式) 我抬头望去,但实际上没有找到想要的东西。 希望我的问题清楚。 由于信誉低,我无法回答这个问题。这是答案 回答 稍作谷歌搜索,我发现’buttonStyle’实际上是’Widget.Button’-