视频播放器的快捷键模块

一个视频播放器的设计与实现系列(四)

Posted by John Mactavish on June 9, 2021

终于到了系列的最后一篇文章,今天我们将引入快捷键模块。

JavaFX 支持两种快捷键机制,一种是 Mnemonic,另一种是 Accelerator。

前者名字不熟悉,它是什么呢?如果你正在用 VSCode、IDEA 等常见的 GUI 软件,不难发现菜单栏上有“文件(File)”、 “帮助(Help)”等菜单,现在按下“Alt+F”,发生了什么,是不是文件菜单打开了,就像你点击了它一样,然后试一试“Alt+H”。 你大概已经猜到了,Mnemonic 就是把快捷键与特定的 ActionEvent 关联在一起。如下所示:

Button btn1 = new Button("_Mnemonic");
Button btn2 = new Button("Mnem_onic");

JavaFX 实际显示按钮时会把文本内容的第一个下划线去除,并把紧跟在下划线后的字母设为对应的 Mnemonic 按键。 现在按下“Alt+M”就会向 btn1 发送 ActionEvent,按下“Alt+O”则向 btn2 发送。

而 Accelerator 机制更加灵活,因而更适合我们。它可以直接把快捷键与特定的 Runnable 实例(即函数)关联在一起, 触发快捷键就会调用指定函数。快捷键与函数间的对应关系保存在 Scene 中。

KeyCombination kc = new KeyCodeCombination(KeyCode.Z, KeyCombination.CONTROL_DOWN);
Runnable rn = ()-> System.out.println("Accelerator key worked");
scene.getAccelerators().put(kc, rn);

在我们的系统中,我们的函数只需触发指定的事件,而不需要与特定组件耦合。看!事件模块的妙处。 又因为我们需要一组函数,所以需要一个类来保存它们间的对应关系。 最好,我们把它设计成一个 Map,这样一来,我们可以把这个类直接利用 putAll 放进 accelerators 中。

@Component
public class KeyboardShortcuts extends HashMap<KeyCombination, Runnable> {
    @Autowired
    public KeyboardShortcuts(ApplicationEventPublisher eventPublisher) {
        Map<KeyCombination, Object> m = Map.of(
                new KeyCodeCombination(KeyCode.RIGHT, KeyCombination.CONTROL_DOWN),
                new MediaSkipTimeEvent(5000),
                new KeyCodeCombination(KeyCode.LEFT, KeyCombination.CONTROL_DOWN),
                new MediaSkipTimeEvent(-5000),
                new KeyCodeCombination(KeyCode.SPACE,KeyCombination.CONTROL_DOWN),
                MediaPlayOrPauseEvent.INSTANCE
        );

        m.forEach((keyCombination, event) -> put(keyCombination, () -> eventPublisher.publishEvent(event)));
    }
}

我们在初始化处注册 accelerators。

@EnableScheduling
@SpringBootApplication
public class App extends Application {
    // ...

    @Override
    public void start(Stage primaryStage) {
        // ...

        Scene scene = new Scene(context.getBean(MainView.class), 1920, 1080);
        scene.getAccelerators().putAll(context.getBean(KeyboardShortcuts.class));
        // set JMetro theme
        new JMetro(Style.LIGHT).setScene(scene);

        // ...
    }
}

好了,大功告成,试一试吧。


本文代码在 https://github.com/gonearewe/MPlayer/tree/e0c63f4bcfcf4e6567c4cd0504fad9ea2d3bbd36 可以找到

vlcj 自己提供了一个基于 Swing 的播放器范例,叫做 vlcj-player,使用到了主要的功能,也可供参考

如果你喜欢我的文章,请我吃根冰棒吧 (o゜▽゜)o ☆

contribution

最后附上 GitHub:https://github.com/gonearewe