gpt4 book ai didi

java - 如何使用 Javafx KeyCombination 覆盖系统默认键盘快捷键,如 Ctrl+C、Ctrl+V?

转载 作者:行者123 更新时间:2023-12-02 08:46:10 26 4
gpt4 key购买 nike

在实现撤消/重做机制时,我编写了以下代码以将粘贴操作添加到我自己的撤消堆栈中。如果我单击菜单项,它会执行事件处理代码,但如果我使用快捷键 Ctrl+V,我的事件处理程序不会执行。

有关更多信息,请参阅下面的代码。

enter image description here

        MenuItem paste = new MenuItem("Paste");

KeyCombination pasteKeyCombination = new KeyCodeCombination(KeyCode.V,KeyCombination.CONTROL_DOWN);

paste.setAccelerator(pasteKeyCombination);

paste.setOnAction(event -> {
System.out.println("Ctrl+V triggered.");
if(clipboard.hasString()){
String pastedText = clipboard.getString();
InsertCommand insertCommand = new InsertCommand(textArea.getCaretPosition(),pastedText,textArea);
insertCommand.execute();
UndoRedo.insertIntoUndoStack(insertCommand);
}
});

如果我使用不同的 KeyCode(例如 Ctrl+J),它工作正常,但不适用于 Ctrl+V。

注意:当我使用 Ctrl+V 时,它似乎直接从系统剪贴板粘贴数据,而不是执行我的代码。

有人可以建议这个问题的解决方案吗?请解释为什么它可以与 Ctrl+J 一起使用,而为什么不能与 Ctrl+V 一起使用?

所有剪切、复制、粘贴快捷方式都存在此问题。

最佳答案

问题是 TextArea (这是一个内部类)的行为添加了许多 EventHandler 来处理各种用户生成的事件(例如按键)。这包括用于剪切、复制、粘贴、撤消、重做、全选等的常用快捷键。然后这些处理程序 consume停止该事件传播的事件。由于菜单项加速器仅在事件冒泡回 Scene 时才起作用,因此 TextArea 行为消耗的事件意味着您的菜单项不会触发。

一种解决方法是在 TextArea 上使用自定义 EventDispatcher 来过滤掉与任意多个按键组合匹配的任何按键事件。所有其他事件都允许正常进行,而其余行为保持不变。这是通过阻止事件到达 TextArea 并让事件进入事件传播的冒泡阶段来实现的,最终让事件冒泡备份场景图。最后一点就是为什么需要使用 EventDispatcher 而不是事件过滤器;在事件过滤器中使用事件将阻止该事件到达 TextArea,但不会让它在场景图中冒泡。

这是一个例子:

import java.util.Set;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventDispatcher;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCombination;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

@Override
public void start(Stage primaryStage) {
MenuItem cutItem = new MenuItem("Cut");
cutItem.setAccelerator(KeyCombination.valueOf("shortcut+x"));
cutItem.setOnAction(e -> System.out.println("CUT"));

MenuItem copyItem = new MenuItem("Copy");
copyItem.setAccelerator(KeyCombination.valueOf("shortcut+c"));
copyItem.setOnAction(e -> System.out.println("COPY"));

MenuItem pasteItem = new MenuItem("Paste");
pasteItem.setAccelerator(KeyCombination.valueOf("shortcut+v"));
pasteItem.setOnAction(e -> System.out.println("PASTE"));

TextArea area = new TextArea();
area.setEventDispatcher(
new FilteringEventDispatcher(
area.getEventDispatcher(),
cutItem.getAccelerator(),
copyItem.getAccelerator(),
pasteItem.getAccelerator()));

VBox root = new VBox(new MenuBar(new Menu("Edit", null, cutItem, copyItem, pasteItem)), area);
VBox.setVgrow(area, Priority.ALWAYS);

primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
}

private static class FilteringEventDispatcher implements EventDispatcher {

private final EventDispatcher delegate;
private final Set<KeyCombination> blacklistedCombos;

public FilteringEventDispatcher(EventDispatcher delegate, KeyCombination... blacklistedCombos) {
this.delegate = delegate;
// Set.of was added in Java 9
this.blacklistedCombos = Set.of(blacklistedCombos);
}

@Override
public Event dispatchEvent(Event event, EventDispatchChain tail) {
if (!(event instanceof KeyEvent) || isPermitted((KeyEvent) event)) {
return delegate.dispatchEvent(event, tail); // forward event to TextArea
}
return event; // skip TextArea and enter the bubbling phase
}

private boolean isPermitted(KeyEvent event) {
return blacklistedCombos.stream().noneMatch(combo -> combo.match(event));
}
}
}

如有必要,您可以通过测试事件的 EventType 进行更具体的过滤(例如,仅过滤 KEY_PRESSED 事件)。您还可以根据您的需要将组合列入白名单而不是将其列入黑名单。

关于java - 如何使用 Javafx KeyCombination 覆盖系统默认键盘快捷键,如 Ctrl+C、Ctrl+V?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61072150/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com