我试图检测在按下“快捷键”时何时触发按钮的操作(可能是通过单击或键盘之类的其他方式)。我找不到从
ActionEvent
按下按键的方法,因此我在场景中放置了按键和释放的事件过滤器,以跟踪按下了哪些按键。然后在按钮的操作中检查是否按下了快捷键。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.HashSet;
import java.util.Set;
public class App extends Application {
private final Set<KeyCode> pressedKeys = new HashSet<>();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Button button = new Button("Click with shortcut key pressed");
button.setOnAction(e -> {
if (pressedKeys.contains(KeyCode.SHORTCUT)) {
System.out.println("Success!");
} else {
System.out.println("Failure!");
}
});
VBox vBox = new VBox(button);
vBox.setStyle("-fx-background-color:red;");
Scene scene = new Scene(vBox);
scene.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
System.out.println("Key pressed: " + e.getCode());
pressedKeys.add(e.getCode());
});
scene.addEventFilter(KeyEvent.KEY_RELEASED, e -> {
System.out.println("Key released: " + e.getCode());
pressedKeys.remove(e.getCode());
});
stage.setScene(scene);
stage.show();
}
public static class AppRunner {
public static void main(String[] args) {
App.main(args);
}
}
}
但是我发现有两个问题:
KeyCode.CONTROL
键,但没有按下 SHORTCUT
键,即使在本例中它们是相同的键。如何以与平台无关的方式检查按下的任何按键是否为快捷键?button.addEventFilter(MouseEvent.MOUSE_CLICKED, e -> {
if (pressedKeys.contains(KeyCode.SHORTCUT)) {
System.out.println("Success!");
} else {
System.out.println("Failure!");
}
});
我还需要它与其他控件上的操作一起使用,例如组合框和文本字段。
编辑:我发现了这种方法的另一个错误。如果用户按住某个键并切换到另一个场景或应用程序然后释放该键,则该场景将不会检测到该键的释放,并且仍会认为该键被按下。因此,我可以采用一种方法来检测按下了哪些键,而无需跟踪每个按键的按下/释放。 MouseEvents 如何获知哪些键被按下,以便它们可以使用
MouseEvent.isShortcutDown()
?这里可以用同样的方法吗?
编辑:要回答jewelsea的更多背景问题,这有点复杂,但想象一下我有一个带有多种类型控件的表单,可用于在表单中设置值,并且需要多次填写表单。因此,我想要一种方法,不仅可以在表单中设置值,还可以修复它或将其设置为默认值,以便下次需要填写时,它将预先填充该值。快捷键是区分设置值而不固定值和设置值并固定值的便捷方法。这适用于通过快捷方式单击组合框中的按钮或下拉项,或者在文本字段中按 Enter 键的同时按住快捷键。我还认为,如果这个问题的答案适用于任何控件上的动作事件,那么对其他人来说会更有用,但即使让它适用于按钮也会很好。
如果您只需要检查在键盘或鼠标事件期间是否按下了快捷键,那么
event.isShortcutDown()
就足够了。
因为它的实现看起来像这样:
public final boolean isShortcutDown() {
switch (Toolkit.getToolkit().getPlatformShortcutKey()) {
case SHIFT:
return shiftDown;
case CONTROL:
return controlDown;
case ALT:
return altDown;
case META:
return metaDown;
default:
return false;
}
}
即使无法访问
Toolkit.getToolkit().getPlatformShortcutKey()
,也有一种方法可以通过以下方式找出哪个键是 shortcut
键:
event.isControlDown(), event.isShiftDown(), event.isAltDown(), event.isMetaDown()
而且您不必担心切换到另一个场景 - 即使在这种情况下,这些方法也会返回正确的值。
以下应用程序创建两个可以切换的场景(“切换场景”和“切换回”按钮)。 第一个包含一些 UI 控件(Button、TextField、ComboBox)以及打印快捷方式检测结果的
KEY_PRESSED
和 MOUSE_PRESSED
事件过滤器。
秒场景的目的只是切换(它不捕获快捷事件)。
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.input.InputEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
Button button = new Button("Click with shortcut key pressed");
TextField text = new TextField("TextField Value");
ComboBox<String> combo = new ComboBox<>(
FXCollections.observableArrayList("ComboBox Value 1", "ComboBox Value 2"));
combo.getSelectionModel().select(0);
Button switcher = new Button("Switch Scene");
VBox vBox = new VBox(button, text, combo, switcher);
vBox.setStyle("-fx-background-color:red;");
vBox.getChildren().forEach(App::addShortcutCaptureFilters);
Scene scene = new Scene(vBox);
Button switcherBack = new Button("Switch Back");
Scene anotherScene = new Scene(new VBox(new Button("Another Button"), switcherBack));
switcher.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> stage.setScene(anotherScene));
switcherBack.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> stage.setScene(scene));
stage.setScene(scene);
stage.show();
}
private static void addShortcutCaptureFilters(Node control) {
control.addEventFilter(KeyEvent.KEY_PRESSED, e -> onShortcutCaptureEvent(control, e, e.isShortcutDown(),
e.isControlDown(), e.isShiftDown(), e.isAltDown(), e.isMetaDown()));
control.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> onShortcutCaptureEvent(control, e, e.isShortcutDown(),
e.isControlDown(), e.isShiftDown(), e.isAltDown(), e.isMetaDown()));
}
private static void onShortcutCaptureEvent(Node control, InputEvent event, boolean shortcut, boolean ctrl,
boolean shift, boolean alt, boolean meta) {
KeyCode specKeyDown = null;
if (ctrl) {
specKeyDown = KeyCode.CONTROL;
} else if (shift) {
specKeyDown = KeyCode.SHIFT;
} else if (alt) {
specKeyDown = KeyCode.ALT;
} else if (meta) {
specKeyDown = KeyCode.META;
}
String ln = shortcut ? "\n" : "";
String title = shortcut ? "SHORTCUT DETECTED" : "not a shortcut";
System.out.println(String.format("%s%s: %s (specKey: %s) %s%s", ln, control.getClass().getSimpleName(), title,
specKeyDown, event.getEventType(), ln));
}
public static class AppRunner {
public static void main(String[] args) {
App.main(args);
}
}
}
输出示例:
Button: not a shortcut (specKey: null) MOUSE_PRESSED
Button: not a shortcut (specKey: null) MOUSE_PRESSED
Button: SHORTCUT DETECTED (specKey: CONTROL) KEY_PRESSED
TextField: not a shortcut (specKey: null) MOUSE_PRESSED
TextField: not a shortcut (specKey: SHIFT) KEY_PRESSED
TextField: not a shortcut (specKey: SHIFT) MOUSE_PRESSED
TextField: SHORTCUT DETECTED (specKey: CONTROL) KEY_PRESSED
ComboBox: not a shortcut (specKey: ALT) MOUSE_PRESSED
ComboBox: not a shortcut (specKey: null) MOUSE_PRESSED
ComboBox: not a shortcut (specKey: ALT) KEY_PRESSED
ComboBox: SHORTCUT DETECTED (specKey: CONTROL) MOUSE_PRESSED
ComboBox: SHORTCUT DETECTED (specKey: CONTROL) KEY_PRESSED
根据注释中的限制,您可以使用
KeyCombination
,它“代表键盘快捷键中使用的按键组合”。总结完整的示例引用这里,
KeyCombination bKey = KeyCombination.keyCombination("Shortcut+[");
Button back = new Button(bKey.getDisplayText());
scene.getAccelerators().put(bKey, this::back);
fire()
方法来调用其现有处理程序:scene.getAccelerators().put(site.k, (Runnable) () -> {
site.button.fire();
});
ActionEvent
监听器以通常的方式处理事件。back.setOnAction((ActionEvent e) -> {
back();
});